60127ea205e0 — pouya@nohup.io 2 years ago
modify and extend the syntax to a simple lisp-like one
M sky/cmd/cfg.c +80 -60
@@ 21,10 21,8 @@ enum
 
 Cfg *cfg;
 
-double runeatof(Rune *s);
-Rune *runestrtok(Rune *s1, Rune *s2);
-struct Skynode *mkskynode(void);
-void *findaddr(Rune *id, int *typ, int *dtyp);
+struct Skynode* mkskynode(void);
+void* findaddr(Rune *id, int *typ, int *dtyp);
 
 int
 cfginit(void)

          
@@ 37,6 35,7 @@ cfginit(void)
 
 	cfg->obs = defaultObs;
 	cfg->camera = defaultCamera;
+	cfg->samplerate = 10;
 	cfg->jd = time(0)/86400.0 + 2440587.5; /* now */
 	cfg->atm = 1;
 

          
@@ 57,39 56,48 @@ cfgterm(void)
 	free(cfg);
 }
 
-int cfginsert(Tok *argv, int argc)
+Tok cfginsert(Tok *argv, int argc)
 {
+	static Tok te[] = {
+		{Tempty, L"success"},
+		{Terror, L"invalid arguments"},
+		{Terror, L"out of memory"},
+	};
 	struct Skynode *head;
 	int typ, dtyp;
 
 	head = cfg->head;
 
-	if(argc != 1 || argv->typ != Tidentifier) return Einvalid;
+	if(argc != 1 || argv->typ != Tidentifier) return te[1];
 
-	if(findaddr(argv->str, &typ, &dtyp)) return Einvalid;
+	if(findaddr(argv->str, &typ, &dtyp)) return te[1];
 	/* the tail node is always pre-allocated but unset */
 	while(head->next)
 		head=head->next;
 
 	if((head->next=mkskynode())==nil)
-		return Ememory;
+		return te[2];
 
 	runestrncpy(head->id, argv->str, Ltoksize+1);
 
-	return 0;
+	return te[0];
 }
 
-int cfgset(Tok *argv, int argc)
+Tok cfgset(Tok *argv, int argc)
 {
+	static Tok te[] = {
+		{Tempty, L"success"},
+		{Terror, L"invalid arguments"},
+	};
 	struct Skynode *head;
 	void *addr;
 	int typ, dtyp;
 
 	head = cfg->head;
 
-	if(argc != 2 || (addr = findaddr(argv->str, &typ, &dtyp)) == nil) return Einvalid;
+	if(argc != 2 || (addr = findaddr(argv->str, &typ, &dtyp)) == nil) return te[1];
 	argv++;
-	if(argv->typ != typ) return Einvalid;
+	if(argv->typ != typ) return te[1];
 
 	switch(dtyp){
 	case DTstr:

          
@@ 102,14 110,52 @@ int cfgset(Tok *argv, int argc)
 		*(int*)addr = runeatof(argv->str);
 		break;
 	default:
-		return Einvalid; /* should not happen */
+		return te[1]; /* should not happen */
 	}
 
-	return 0;
+	return te[0];
 }
 
-int cfgdraw(Tok *argv, int argc)
+Tok cfgget(Tok *argv, int argc)
 {
+	static Tok te[] = {
+		{Tempty, L"success"},
+		{Terror, L"invalid arguments"},
+	};
+	struct Skynode *head;
+	void *addr;
+	int typ, dtyp;
+
+	head = cfg->head;
+
+	if(argc != 1 || (addr = findaddr(argv->str, &typ, &dtyp)) == nil) return te[1];
+
+	switch(dtyp){
+	case DTstr:
+		runestrncpy(te[0].str, addr, Ltoksize+1);
+		te[0].typ = Tstr;
+		break;
+	case DTdouble:
+		runesnprint(te[0].str, Ltoksize+1, "%f", *(double*)addr);
+		te[0].typ = Tdecimal;
+		break;
+	case DTint:
+		runesnprint(te[0].str, Ltoksize+1, "%d", *(int*)addr);
+		te[0].typ = Tdecimal;
+		break;
+	default:
+		return te[1]; /* should not happen */
+	}
+
+	return te[0];
+}
+
+Tok cfgdraw(Tok *argv, int argc)
+{
+	static Tok te[] = {
+		{Tempty, L"success"},
+		{Terror, L"invalid arguments"},
+	};
 	struct Skynode *head;
 	Hzloc hz;
 	Planar p;

          
@@ 118,54 164,22 @@ int cfgdraw(Tok *argv, int argc)
 
 	head = cfg->head;
 
-	if(argc != 0) return Einvalid;
+	if(argc != 0) return te[1];
 
 	/* the tail node is always pre-allocated but unset */
 	while(head->next){
-		hz = eq2hz(gx2eq00(head->gx), cfg->obs.g, cfg->jd, 0, 0);
+		hz = eq2hz(head->eq, cfg->obs.g, cfg->jd, 0, 0);
 		if(cfg->atm) hz.z += saemundsson(&cfg->obs, hz.z);
 		p = hz2pxl(&cfg->camera, hz);
-		pt.x = p.x + cfg->camera.wpx/2; pt.y = p.y + cfg->camera.hpx/2;
+		pt.x = (p.x + cfg->camera.wpx/2)/cfg->samplerate;
+		pt.y = (p.y + cfg->camera.hpx/2)/cfg->samplerate;
 		c.r = head->r; c.g = head->g; c.b = head->b;
+		DBPRINT(10, "cfg.c:cfgdraw marker %d,%d c(%d,%d,%d) s%d L\"%S\"\n", pt.x, pt.y, c.r, c.g, c.b, head->size, head->str);
 		marker(screen, pt, c, head->size, Mdisc, head->str);
 		head=head->next;
 	}
 
-	return 0;
-}
-
-double
-runeatof(Rune *s)
-{
-	char cs[Ltoksize+1], *c;
-	int i;
-
-	for(i=0, c=cs; i<Ltoksize && *s; i++)
-		*c++ = *s++;
-	*c = '\0';
-
-	return atof(cs);
-}
-
-Rune*
-runestrtok(Rune *s, Rune *b)
-{
-	static Rune *saved;
-	Rune *sc, *bc;
-
-	if(s == 0) s = saved;
-
-	sc = s;
-	while(*sc){
-		for(bc=b; *bc; bc++) if(*sc == *bc){
-			*sc++ = L'\0';
-			saved = sc;
-			return s;
-		}
-		sc++;
-	}
-	saved = L"";
-	return s;
+	return te[0];
 }
 
 struct Skynode*

          
@@ 234,12 248,12 @@ findaddr(Rune *id, int *typ, int *dtyp)
 		}
 		if(!runestrcmp(t, L"wpx")){
 			*typ = Tdecimal;
-			*dtyp = DTdouble;
+			*dtyp = DTint;
 			return &cfg->camera.wpx;
 		}
 		if(!runestrcmp(t, L"hpx")){
 			*typ = Tdecimal;
-			*dtyp = DTdouble;
+			*dtyp = DTint;
 			return &cfg->camera.hpx;
 		}
 		if(!runestrcmp(t, L"angle")){

          
@@ 259,6 273,12 @@ findaddr(Rune *id, int *typ, int *dtyp)
 		return nil;
 	}
 
+	if(!runestrcmp(t, L"samplerate")){
+		*typ = Tdecimal;
+		*dtyp = DTint;
+		return &cfg->samplerate;
+	}
+
 	if(!runestrcmp(t, L"jd")){
 		*typ = Tdecimal;
 		*dtyp = DTdouble;

          
@@ 281,15 301,15 @@ findaddr(Rune *id, int *typ, int *dtyp)
 				*dtyp = DTstr;
 				return head->str;
 			}
-			if(!runestrcmp(t, L"gx")){
+			if(!runestrcmp(t, L"eq")){
 				if((t = runestrtok(0, L".")) == 0) return nil;
 				DBPRINT(20, "gx. t=%S ", t);
 				*typ = Tdecimal;
 				*dtyp = DTdouble;
-				if(!runestrcmp(t, L"b"))
-					return &head->gx.b;
-				if(!runestrcmp(t, L"l"))
-					return &head->gx.l;
+				if(!runestrcmp(t, L"ra"))
+					return &head->eq.ra;
+				if(!runestrcmp(t, L"dec"))
+					return &head->eq.dec;
 
 				return nil;
 			}

          
M sky/cmd/cmd.c +49 -32
@@ 13,30 13,31 @@ 
 Lexer l;
 
 struct Cmdnode *mkcmdnode(void);
+Tok cmdeval(Cmdreg* reg, int depth);
 int eqsig(Cmd *c1, Cmd *c2);
-int (*(getfun)(struct Cmdnode*, Cmd*))(Tok*, int);
+Tok (*(getfun)(struct Cmdnode*, Cmd*))(Tok*, int);
 
-Cmdctxt*
-mkcmdctxt(int fd)
+Cmdreg*
+mkcmdreg(int fd)
 {
-	Cmdctxt *ctxt;
-	if((ctxt=malloc(sizeof(Cmdctxt)))==nil)
+	Cmdreg *reg;
+	if((reg=malloc(sizeof(Cmdreg)))==nil)
 		return nil;
-	linit(&ctxt->l, fd, lexstart());
-	if((ctxt->head=mkcmdnode())==nil){
-		free(ctxt);
+	linit(&reg->l, fd, lexstart());
+	if((reg->head=mkcmdnode())==nil){
+		free(reg);
 		return nil;
 	}
 
-	return ctxt;
+	return reg;
 }
 
 
 int
-cmdreg(Cmdctxt *ctxt, Cmd *c)
+cmdregister(Cmdreg *reg, Cmd *c)
 {
 	struct Cmdnode *head;
-	head = ctxt->head;
+	head = reg->head;
 
 	/* the tail node is always pre-allocated but unset */
 	while(head->next){

          
@@ 56,10 57,10 @@ cmdreg(Cmdctxt *ctxt, Cmd *c)
 }
 
 void
-cmdterm(Cmdctxt *ctxt)
+cmdterm(Cmdreg *reg)
 {
 	struct Cmdnode *head, *nxt;
-	head = ctxt->head;
+	head = reg->head;
 
 	while(head){
 		nxt = head->next;

          
@@ 68,58 69,73 @@ cmdterm(Cmdctxt *ctxt)
 		head = nxt;
 	}
 
-	lterm(&ctxt->l);
-	free(ctxt);
+	lterm(&reg->l);
+	free(reg);
 }
 
-void
-cmdproc(void *ctxt)
+Tok
+cmdeval(Cmdreg* reg, int depth)
 {
 	struct Cmdnode *head;
 	Tok t, argv[Cmaxargs];
 	Cmd c;
-	int (*efun)(Tok*, int);
+	Tok (*efun)(Tok*, int);
 	char *err;
 
-	head = ((Cmdctxt*)ctxt)->head;
+	head = reg->head;
 	memset(&c, 0, sizeof(Cmd));
 
-	while(t = lnexttok(&((Cmdctxt*)ctxt)->l), t.typ != Teof){
-		DBPRINT(10, "tok: %d(%S)\n", t.typ, t.str);
+	while(t = lnexttok(&reg->l), t.typ != Teof){
+eval:		DBPRINT(10, "tok: %d(%S)\n", t.typ, t.str);
 		switch(t.typ){
 		case Terror:
 			err = "parse error";
-error:		fprint(2, "%s in cmd %S (last token: %S)\n", err, *c.str ? c.str : L"nil", t.str);
-			memset(&c, 0, sizeof(Cmd));
-			break;
+error:		fprint(2, "%s in cmd %S L\"%S\"\n", err, *c.str ? c.str : L"nil", t.str);
+			return t;
 		case Tcmd:
 			runestrncpy(c.str, t.str, Ltoksize+1);
 			break;
-		case Teos:
+		case Tpclose:
+			if(depth <= 0){
+				err = "unmatched pclose";
+				goto error;
+			}
+
 			if((efun = getfun(head, &c)) == nil){
 				err = "unrecognised function signature";
 				goto error;
 			}
-			if((*efun)(argv, c.argc) < 0){
+			if((t = (*efun)(argv, c.argc)), t.typ == Terror){
 				err = "invalid data";
 				goto error;
 			}
 			DBIF(10) {
-				fprint(2, "cmd %S with args in reverse:", c.str);
-				while(c.argc) fprint(2, " %S", argv[--c.argc].str);
+				fprint(2, "cmd %S with %d arg(s) in reverse:", c.str, c.argc);
+				while(c.argc--) fprint(2, " %d(%S)", argv[c.argc].typ, argv[c.argc].str);
 				fprint(2, ": success\n");
 			}
-			memset(&c, 0, sizeof(Cmd));
-			break;
+			return t;
+		case Tpopen:
+			t = cmdeval(reg, depth+1);
+			goto eval;
 		case Tidentifier:
 		case Tdecimal:
 		case Tstr:
 			c.argtyp[c.argc] = t.typ;
 			argv[c.argc++] = t;
 			break;
-			break;
 		}
 	}
+	return t;
+}
+
+void
+cmdproc(void *reg)
+{
+	Tok t;
+	while(t = cmdeval(reg, 0), t.typ != Teof){
+		DBPRINT(10, "eval: %d(%S)\n", t.typ, t.str);
+	}
 }
 
 struct Cmdnode*

          
@@ 144,6 160,7 @@ eqsig(Cmd *c1, Cmd *c2)
 	int i, *a1, *a2;
 
 	if(!c1 || !c2) return 0;
+	/* negative argc matches any number */
 	if(runestrncmp(c1->str, c2->str, Ltoksize+1) || c1->argc != c2->argc) return 0;
 	for(i=0, a1=c1->argtyp, a2=c2->argtyp; i<c1->argc; i++)
 		if(*a1++ != *a2++) return 0;

          
@@ 151,7 168,7 @@ eqsig(Cmd *c1, Cmd *c2)
 	return 1;	
 }
 
-int (*(getfun)(struct Cmdnode *h, Cmd *c))(Tok*, int)
+Tok (*(getfun)(struct Cmdnode *h, Cmd *c))(Tok*, int)
 {
 	/* last node is always unset */
 	while(h->next){

          
M sky/cmd/dat.h +12 -7
@@ 1,14 1,16 @@ 
 typedef struct Cmd Cmd;
-typedef struct Cmdctxt Cmdctxt;
+typedef struct Cmdreg Cmdreg;
 typedef struct Cfg Cfg;
 
 enum
 {
 	Teof = Leof,
 	Terror = -10,
-	Tcomment = 0,
+	Tempty = 0,
+	Tcomment,
+	Tpopen,
+	Tpclose,
 	Tcmd,
-	Teos,
 	Tidentifier,
 	Tdecimal,
 	Tstr,

          
@@ 17,6 19,7 @@ enum
 enum
 {
 	Cmaxargs = 32,
+	Cmaxdepth = 16,
 };
 
 enum

          
@@ 30,7 33,7 @@ struct Cmd
 {
 	Rune str[Ltoksize+1];
 	int argc, argtyp[Cmaxargs];
-	int (*fun)(Tok*, int);
+	Tok (*fun)(Tok*, int);
 };
 
 struct Cmdnode

          
@@ 39,7 42,7 @@ struct Cmdnode
 	struct Cmdnode *next;
 };
 
-struct Cmdctxt
+struct Cmdreg
 {
 	struct Cmdnode *head;
 	Lexer l;

          
@@ 49,7 52,7 @@ struct Skynode
 {
 	Rune id[Ltoksize+1];
 	Rune str[Ltoksize+1];
-	Gxloc gx;
+	Eqloc eq;
 	int r,g,b;
 	int size;
 

          
@@ 60,10 63,12 @@ struct Cfg
 {
 	Obs obs;
 	Camera camera;
+	int samplerate;
 	double jd;
 	int atm;
 
 	struct Skynode *head;	
 };
 
-extern Cfg *cfg;
+extern Cfg* cfg;
+extern Cmdreg* cmdreg;

          
M sky/cmd/fns.h +20 -7
@@ 2,14 2,27 @@ 
 State lexstart(void);
 
 /* cmd.c */
-Cmdctxt *mkcmdctxt(int fd);
-int cmdreg(Cmdctxt *ctxt, Cmd *c);
-void cmdproc(void *ctxt);
-void cmdterm(Cmdctxt *ctxt);
+Cmdreg *mkcmdreg(int fd);
+int cmdregister(Cmdreg *reg, Cmd *c);
+void cmdproc(void *reg);
+void cmdterm(Cmdreg *reg);
 
 /* cfg.c */
 int cfginit(void);
 void cfgterm(void);
-int cfginsert(Tok *argv, int argc);
-int cfgset(Tok *argv, int argc);
-int cfgdraw(Tok *argv, int argc);
+Tok cfginsert(Tok *argv, int argc);
+Tok cfgset(Tok *argv, int argc);
+Tok cfgget(Tok *argv, int argc);
+Tok cfgdraw(Tok *argv, int argc);
+
+/* ops.c */
+void opinit(void);
+
+/* util.c */
+double runeatof(Rune *s);
+Rune* runestrtok(Rune *s, Rune *b);
+
+/* main.c */
+void redraw(void);
+void resized(void);
+void cleanup(void);
  No newline at end of file

          
M sky/cmd/lex.c +63 -47
@@ 16,6 16,8 @@ State scmd(Lexer *l, void *aux);
 State scomment(Lexer *l, void *aux);
 State sswtch(Lexer *l, void *aux);
 State seos(Lexer *l, void *aux);
+State spopen(Lexer *l, void *aux);
+State spclose(Lexer *l, void *aux);
 State sidentifier(Lexer *l, void *aux);
 State sdecimal(Lexer *l, void *aux);
 State sstr(Lexer *l, void *aux);

          
@@ 25,7 27,7 @@ lexstart(void)
 {
 	State nxt;
 
-	nxt.fun = &scmd;
+	nxt.fun = &spopen;
 	return nxt;
 }
 

          
@@ 52,7 54,47 @@ serror(Lexer *l, void *aux)
 
 	lemit(l, Terror);
 
-	nxt.fun = &scmd;
+	nxt.fun = &spopen;
+	return nxt;
+}
+
+State
+sswtch(Lexer *l, void *aux)
+{
+	State nxt;
+
+	lacceptrun(l, L" \t\n");
+	lignore(l);
+
+	switch(lpeek(l)){
+	case L'#':
+		nxt.fun = &scomment;
+		return nxt;
+	case L'"':
+		nxt.fun = &sstr;
+		return nxt;
+	case L'(':
+		nxt.fun = &spopen;
+		return nxt;
+	case L')':
+		nxt.fun = &spclose;
+		return nxt;
+	}
+
+	if(laccept(l, L"0123456789-+.")){
+		lbackup(l);
+		nxt.fun = &sdecimal;
+		return nxt;
+	}
+
+	if(laccept(l, L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_")){
+		lbackup(l);
+		nxt.fun = &sidentifier;
+		return nxt;
+	}
+
+	nxt.fun = &serror;
+	nxt.aux = "sswtch";
 	return nxt;
 }
 

          
@@ 66,30 108,22 @@ scmd(Lexer *l, void *aux)
 	lacceptrun(l, L" \t\n");
 	lignore(l);
 
-	if(laccept(l, L";")){
-		lbackup(l);
-		nxt.fun = &seos;
-		return nxt;
-	}
-
-	lacceptuntil(l, L" \t\n;");
+	lacceptuntil(l, L" \t\n)");
 
 	if((len = llen(l)) < 0){
 		nxt.fun = &serror;
 		nxt.aux = "cmd";
 		return nxt;
-	}else if(len == 0){
-		nxt.fun = &scmd;
+	}
+
+	if(*l->b == L'#'){
+		nxt.fun = &scomment;
 		return nxt;
 	}
-		
-	if(*l->b == L'#')
-		nxt.fun = &scomment;
-	else{
-		lemit(l, Tcmd);
-		nxt.fun = &sswtch;
-	}
 
+	lemit(l, Tcmd);
+
+	nxt.fun = &sswtch;
 	return nxt;
 }
 

          
@@ 111,59 145,42 @@ scomment(Lexer *l, void *aux)
 }
 
 State
-sswtch(Lexer *l, void *aux)
+spopen(Lexer *l, void *aux)
 {
 	State nxt;
 
 	lacceptrun(l, L" \t\n");
 	lignore(l);
 
-	switch(lpeek(l)){
-	case L';':
-		nxt.fun = &seos;
-		return nxt;
-	case L'#':
-		nxt.fun = &scomment;
-		return nxt;
-	case L'"':
-		nxt.fun = &sstr;
+	if(!laccept(l, L"(")){
+		nxt.fun = &serror;
+		nxt.aux = "popen";
 		return nxt;
 	}
 
-	if(laccept(l, L"0123456789-+.")){
-		lbackup(l);
-		nxt.fun = &sdecimal;
-		return nxt;
-	}
+	lemit(l, Tpopen);
 
-	if(laccept(l, L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_")){
-		lbackup(l);
-		nxt.fun = &sidentifier;
-		return nxt;
-	}
-
-	nxt.fun = &serror;
-	nxt.aux = "sswtch";
+	nxt.fun = &scmd;
 	return nxt;
 }
 
 State
-seos(Lexer *l, void *aux)
+spclose(Lexer *l, void *aux)
 {
 	State nxt;
 
 	lacceptrun(l, L" \t\n");
 	lignore(l);
 
-	if(!laccept(l, L";")){
+	if(!laccept(l, L")")){
 		nxt.fun = &serror;
-		nxt.aux = "eos";
+		nxt.aux = "pclose";
 		return nxt;
 	}
 
-	lemit(l, Teos);
+	lemit(l, Tpclose);
 
-	nxt.fun = &scmd;
+	nxt.fun = &sswtch;
 	return nxt;
 }
 

          
@@ 253,4 270,3 @@ sstr(Lexer *l, void *aux)
 	nxt.fun = &sswtch;
 	return nxt;
 }
-

          
M sky/cmd/mkfile +2 -0
@@ 9,9 9,11 @@ LIB=../libgfx/libgfx.a ../liblex/liblex.
 
 OFILES=\
 	skywatch.$O\
+	ops.$O\
 	cfg.$O\
 	cmd.$O\
 	lex.$O\
+	util.$O\
 
 HFILES=\
 	dat.h\

          
A => sky/cmd/ops.c +172 -0
@@ 0,0 1,172 @@ 
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <thread.h>
+#include <draw.h>
+
+#include "lex.h"
+#include "sky.h"
+#include "gfx.h"
+
+#include "dat.h"
+#include "fns.h"
+
+Cmdreg* cmdreg;
+
+/* commands */
+Tok opquit(Tok *argv, int argc);
+Tok opredraw(Tok *argv, int argc);
+Tok opresize(Tok *argv, int argc);
+Tok optest(Tok *argv, int argc);
+
+/* functions */
+Tok opadd(Tok *argv, int argc);
+Tok opmult(Tok *argv, int argc);
+Tok ophms(Tok *argv, int argc);
+Tok opdegms(Tok *argv, int argc);
+
+void
+opinit(void)
+{
+	int i;
+	Cmd *c, clist[] = {
+		{L"insert", 1, {Tidentifier,}, &cfginsert},
+		{L"get", 1, {Tidentifier,}, &cfgget},
+		{L"set", 2, {Tidentifier, Tdecimal,}, &cfgset},
+		{L"set", 2, {Tidentifier, Tstr,}, &cfgset},
+		{L"draw", 0, {0,}, &opredraw},
+		{L"resize", 0, {0,}, &opresize},
+		{L"bye", 0, {0,}, &opquit},
+		{L"test", 0, {0,}, &optest},
+
+		{L"add", 2, {Tdecimal, Tdecimal,}, &opadd},
+		{L"mult", 2, {Tdecimal, Tdecimal,}, &opmult},
+		{L"hms", 3, {Tdecimal, Tdecimal, Tdecimal}, &ophms},
+		{L"degms", 3, {Tdecimal, Tdecimal, Tdecimal}, &opdegms},
+	};
+
+	if(cfginit() < 0)
+		sysfatal("cfginit");
+
+	if((cmdreg = mkcmdreg(0)) == nil)
+		sysfatal("mkcmdreg: out of memory");
+
+	for(i=0, c=clist; i<nelem(clist); i++, c++)
+		if(cmdregister(cmdreg, c) < 0)
+			sysfatal("cmdregister: can't register %S", c->str);
+}
+
+Tok
+opquit(Tok *argv, int argc)
+{
+	Tok t = {Tempty, L"success (hopefully)"};
+
+	fprint(2, "cleaning up...\n");
+	cmdterm(cmdreg);
+	cfgterm();
+
+	cleanup();
+
+	threadexitsall(nil);
+
+	return t; /* never reached */
+}
+
+Tok
+opredraw(Tok *argv, int argc)
+{
+	Tok t = {Tempty, L"success (hopefully)"};
+	redraw();
+	return t;
+}
+
+Tok
+opresize(Tok *argv, int argc)
+{
+	Tok t = {Tempty, L"success (hopefully)"};
+	resized();
+	return t;
+}
+
+Tok
+optest(Tok *argv, int argc)
+{
+	Tok t = {Tempty, L"success (hopefully)"};
+	RGBi c = {255, 0, 0};
+	print("%d %d %d %d", c.buf[0], c.buf[1], c.buf[2], marker(screen, Pt(50, 50), c, 5, Mdisc, L"hello"));
+
+	return t;
+}
+
+Tok
+opadd(Tok *argv, int argc)
+{
+	Tok t = {Terror, "invalid arguments"};
+	double r;
+
+	if(argc < 2) return t;
+
+	r = 0;
+	while(argc--){
+		if(argv->typ != Tdecimal) return t;
+		r += runeatof(argv++->str);
+	}
+	t.typ = Tdecimal;
+	runesnprint(t.str, Ltoksize+1, "%f", r);
+	return t;
+}
+
+Tok
+opmult(Tok *argv, int argc)
+{
+	Tok t = {Terror, "invalid arguments"};
+	double r;
+
+	if(argc < 2) return t;
+
+	r = 1;
+	while(argc--){
+		if(argv->typ != Tdecimal) return t;
+		r *= runeatof(argv++->str);
+	}
+	t.typ = Tdecimal;
+	runesnprint(t.str, Ltoksize+1, "%f", r);
+	return t;
+}
+
+Tok
+ophms(Tok *argv, int argc)
+{
+	Tok t = {Terror, "invalid arguments"};
+	double a[3], *ap;
+
+	if(argc != 3) return t;
+
+	ap = a;
+	while(argc--){
+		if(argv->typ != Tdecimal) return t;
+		*ap++ = runeatof(argv++->str);
+	}
+	t.typ = Tdecimal;
+	runesnprint(t.str, Ltoksize+1, "%f", hms2rad(a[0], a[1], a[2]));
+	return t;
+}
+
+Tok
+opdegms(Tok *argv, int argc)
+{
+	Tok t = {Terror, "invalid arguments"};
+	double a[3], *ap;
+
+	if(argc != 3) return t;
+
+	ap = a;
+	while(argc--){
+		if(argv->typ != Tdecimal) return t;
+		*ap++ = runeatof(argv++->str);
+	}
+	t.typ = Tdecimal;
+	runesnprint(t.str, Ltoksize+1, "%f", degms2rad(a[0], a[1], a[2]));
+	return t;
+}
+

          
M sky/cmd/skywatch.c +40 -78
@@ 3,6 3,7 @@ 
 #include <bio.h>
 #include <thread.h>
 #include <draw.h>
+#include <mouse.h>
 
 #include "lex.h"
 #include "sky.h"

          
@@ 16,113 17,74 @@ enum
 	STACK = 512*1024,
 };
 
-Cmdctxt *cmdctxt;
-
-void cleanup(void);
-void drawscreen(void);
-
-int opquit(Tok *argv, int argc);
-int opredraw(Tok *argv, int argc);
-
-int
-opquit(Tok *argv, int argc)
-{
-	cleanup();
-	threadexitsall(nil);
-
-	return 0;
-}
-
-int
-opredraw(Tok *argv, int argc)
-{
-	drawscreen();
-	return cfgdraw(argv, argc);
-}
+Mousectl *mc;
 
 void
-drawscreen(void)
+resized(void)
 {
 	if(getwindow(display, Refnone) < 0)
 		sysfatal("can't reattach to window");
 
-	print("skywatch.c:resized: %d, %d\n", cfg->camera.wpx, cfg->camera.hpx); 
-	resize(cfg->camera.wpx, cfg->camera.hpx);
+	resize(cfg->camera.wpx/cfg->samplerate, cfg->camera.hpx/cfg->samplerate);
 
-	draw(screen, screen->r, display->black, nil, ZP);
-	flushimage(display, 1);
+	redraw();
 }
 
 void
-init(void)
+redraw(void)
 {
-	Cmd c;
-
-	if(cfginit() < 0)
-		sysfatal("can't init config");
-
-	if((cmdctxt = mkcmdctxt(0)) == nil)
-		sysfatal("out of memory");
-
-	runestrcpy(c.str, L"insert");
-	c.argc = 1;
-	c.argtyp[0] = Tidentifier;
-	c.fun = &cfginsert;
-	if(cmdreg(cmdctxt, &c) < 0)
-		sysfatal("can't register command");
+	if(getwindow(display, Refnone) < 0)
+		sysfatal("can't reattach to window");
 
-	runestrcpy(c.str, L"set");
-	c.argc = 2;
-	c.argtyp[0] = Tidentifier;
-	c.argtyp[1] = Tdecimal;
-	c.fun = &cfgset;
-	if(cmdreg(cmdctxt, &c) < 0)
-		sysfatal("can't register command");
-
-	runestrcpy(c.str, L"set");
-	c.argc = 2;
-	c.argtyp[0] = Tidentifier;
-	c.argtyp[1] = Tstr;
-	c.fun = &cfgset;
-	if(cmdreg(cmdctxt, &c) < 0)
-		sysfatal("can't register command");
-
-	runestrcpy(c.str, L"draw");
-	c.argc = 0;
-	c.fun = &opredraw;
-	if(cmdreg(cmdctxt, &c) < 0)
-		sysfatal("can't register command");
-
-	runestrcpy(c.str, L"bye");
-	c.argc = 0;
-	c.fun = &opquit;
-	if(cmdreg(cmdctxt, &c) < 0)
-		sysfatal("can't register command");
+	draw(screen, screen->r, display->black, nil, ZP);
+	cfgdraw(nil, 0);
+	flushimage(display, 0);
 }
 
 void
 cleanup(void)
 {
-	fprint(2, "cleaning up...\n");
-	cmdterm(cmdctxt);
-	cfgterm();
+	closemouse(mc);
 }
 
 void
 threadmain(int argc, char *argv[])
 {
 	int rm;
+	Mouse mm;
+	Alt a[] = {
+		{nil, &rm, CHANRCV},
+		{nil, &mm, CHANRCV},
+		{nil, nil, CHANEND},
+	};
 
-	init();
+	opinit();
 
 	if(newwindow(nil) < 0 || initdraw(nil, nil, "skywatch") < 0 || gfxinit() < 0)
 		sysfatal("failed to initialise draw: %r");
 
-	drawscreen();
+	if((mc = initmouse(nil, screen)) == nil)
+		sysfatal("initmouse: %r");
+
+	rm = 0;
+	a[0].c = mc->resizec;
+	a[1].c = mc->c;
+
+	resized();
+
+	proccreate(&cmdproc, cmdreg, STACK);
 
-	proccreate(&cmdproc, cmdctxt, STACK);
-
-	for(;;);
+	for(;;) switch(alt(a)){
+	case 0:
+		print("mouse: resized\n");
+		resized();
+		break;
+	case 1:
+		print("mouse: mouse\n");
+		break;
+	default:
+		sysfatal("shouldn't happen");
+	}		
 }
 
 

          
A => sky/cmd/util.c +47 -0
@@ 0,0 1,47 @@ 
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <bio.h>
+#include <draw.h>
+
+#include "debug.h"
+#include "lex.h"
+#include "sky.h"
+#include "gfx.h"
+
+#include "dat.h"
+#include "fns.h"
+
+double
+runeatof(Rune *s)
+{
+	char cs[Ltoksize+1], *c;
+	int i;
+
+	for(i=0, c=cs; i<Ltoksize && *s; i++)
+		*c++ = *s++;
+	*c = '\0';
+
+	return atof(cs);
+}
+
+Rune*
+runestrtok(Rune *s, Rune *b)
+{
+	static Rune *saved;
+	Rune *sc, *bc;
+
+	if(s == 0) s = saved;
+
+	sc = s;
+	while(*sc){
+		for(bc=b; *bc; bc++) if(*sc == *bc){
+			*sc++ = L'\0';
+			saved = sc;
+			return s;
+		}
+		sc++;
+	}
+	saved = L"";
+	return s;
+}

          
M sky/libgfx/gfx.c +8 -7
@@ 42,27 42,28 @@ marker(Image *dst, Point pt, RGBi c, int
 
 	if(!setpen(c)) return Gfailed;
 
+	pt = addpt(pt, screen->r.min);
 	switch(mark){
 	case Msquare:
-		line(dst, pt, pt, Endsquare, Endsquare, size, pen, pt);
+		line(dst, pt, pt, Endsquare, Endsquare, size, pen, ZP);
 		break;
 	case Mdisc:
-		line(dst, pt, pt, Enddisc, Enddisc, size, pen, pt);
+		line(dst, pt, pt, Enddisc, Enddisc, size, pen, ZP);
 		break;
 	case Mdiamond:
 		sh[0] = addpt(pt, Pt(-size,0));
 		sh[1] = addpt(pt, Pt(0,-size));
 		sh[2] = addpt(pt, Pt(size,0));
 		sh[3] = addpt(pt, Pt(0,size));
-		fillpoly(dst, sh, 4, 0, pen, pt);
+		fillpoly(dst, sh, 4, 0, pen, ZP);
 		break;
 	case Mplus:
-		line(dst, addpt(pt, Pt(0, -size)), addpt(pt, Pt(0, size)), Endsquare, Endsquare, 1, pen, pt);
-		line(dst, addpt(pt, Pt(-size, 0)), addpt(pt, Pt(size, 0)), Endsquare, Endsquare, 1, pen, pt);
+		line(dst, addpt(pt, Pt(0, -size)), addpt(pt, Pt(0, size)), Endsquare, Endsquare, 1, pen, ZP);
+		line(dst, addpt(pt, Pt(-size, 0)), addpt(pt, Pt(size, 0)), Endsquare, Endsquare, 1, pen, ZP);
 		break;
 	case Mcross:
-		line(dst, addpt(pt, Pt(-size, -size)), addpt(pt, Pt(size, size)), Endsquare, Endsquare, 1, pen, pt);
-		line(dst, addpt(pt, Pt(-size, size)), addpt(pt, Pt(size, -size)), Endsquare, Endsquare, 1, pen, pt);
+		line(dst, addpt(pt, Pt(-size, -size)), addpt(pt, Pt(size, size)), Endsquare, Endsquare, 1, pen, ZP);
+		line(dst, addpt(pt, Pt(-size, size)), addpt(pt, Pt(size, -size)), Endsquare, Endsquare, 1, pen, ZP);
 		break;
 	default:
 		return Gunsupported;