ref: f7cd83ffe6a65578a9f1c89646facbcbfd7179a1
dir: /parse.c/
#include <u.h>
#include <libc.h>
#include <ctype.h>
#include "dat.h"
#include "fns.h"
Sym *sym;
int nsym;
int Δx, Δy;
static char*
esmprint(char *fmt, ...)
{
char *p;
va_list arg;
va_start(arg, fmt);
p = vsmprint(fmt, arg);
va_end(arg);
if(p == nil)
sysfatal("smprint: %r");
return p;
}
static char *
estrdup(char *s)
{
if((s = strdup(s)) == nil)
sysfatal("estrdup: %r");
setmalloctag(s, getcallerpc(&s));
return s;
}
static void *
erealloc(void *p, ulong n)
{
if((p = realloc(p, n)) == nil)
sysfatal("realloc: %r");
setmalloctag(p, getcallerpc(&p));
return p;
}
static void *
emalloc(ulong n)
{
void *p;
if((p = mallocz(n, 1)) == nil)
sysfatal("emalloc: %r");
setmalloctag(p, getcallerpc(&n));
return p;
}
static void
nuketok(void)
{
char **p;
for(p=tok; p<tok+ntok; p++)
free(*p);
free(tok);
tok = nil;
ntok = 0;
}
static char **
newtok(char *s)
{
char **p;
tok = erealloc(tok, ++ntok * sizeof *tok);
p = tok + ntok - 1;
*p = s;
return p;
}
static char *
addtok(char *s, int n)
{
char **p;
p = newtok(s);
*p = emalloc(n + 1);
memcpy(*p, s, n);
return *p;
}
static Sym *
newsym(char *name)
{
Sym *s;
sym = erealloc(sym, ++nsym * sizeof *sym);
s = sym + nsym - 1;
s->iname = esmprint("$%zd", s - sym + 1);
s->cname = esmprint("﹩im[%zd]", s - sym);
s->name = name == nil ? esmprint("﹩%zd", s - sym + 1) : estrdup(name);
return s;
}
static Sym *
getsym(char *name, int n)
{
Sym *s;
if(n == 0)
n = strlen(name);
for(s=sym; s<sym+nsym; s++)
if(strncmp(s->name, name, n) == 0 && strlen(s->name) == n
|| strncmp(s->iname, name, n) == 0 && strlen(s->iname) == n)
return s;
return nil;
}
static Sym *
addsym(char *name)
{
Sym *s;
if((s = getsym(name, 0)) == nil)
s = newsym(name);
return s;
}
static void
cleanup(void)
{
Sym *s;
nuketok();
for(s=sym; s<sym+nsym; s++)
s->ref = 0;
}
static void
fnwrite(int argc, char **argv)
{
int n, fd, dfd;
uchar buf[65536];
Sym *s;
if(argc != 3){
fprint(2, "usage: w name path\n");
return;
}
if((s = getsym(argv[1], 0)) == nil){
fprint(2, "fnwrite: no such image %s\n", argv[1]);
return;
}
if(strcmp(argv[2], s->path) == 0){
fprint(2, "not overwriting image with itself\n");
return;
}
if((fd = open(s->path, OREAD)) < 0){
fprint(2, "open: %r\n");
return;
}
if((dfd = create(argv[2], OWRITE, 0666)) < 0){
fprint(2, "create: %r\n");
return;
}
while((n = read(fd, buf, sizeof buf)) > 0)
if(write(dfd, buf, n) != n){
n = -1;
break;
}
close(fd);
close(dfd);
if(n < 0)
fprint(2, "fnwrite: %r\n");
}
static void
fnadd(int argc, char **argv)
{
char *path;
Sym *s;
if(argc < 2 || argc > 3){
fprint(2, "usage: r name [path]\n");
return;
}
s = addsym(argv[1]);
path = argc < 3 ? argv[1] : argv[2];
if(access(path, OREAD) < 0){
fprint(2, "access %s: %r\n", path);
return;
}
s->path = esmprint("%s%s%s",
path[0] == '/' ? "" : wdir,
path[0] == '/' ? "" : "/",
path);
}
static void
fndisplay(int argc, char **argv)
{
int i;
Sym *s;
if(argc == 1){
if(nsym > 0)
show(sym[nsym-1].path);
return;
}
for(i=1; i<argc; i++){
if((s = getsym(argv[i], 0)) != nil)
show(s->path);
else
fprint(2, "fndisplay: no such image %s\n", argv[i]);
}
}
static void
fnsize(int argc, char **argv)
{
char *p;
if(argc != 3){
fprint(2, "usage: s width height\n");
return;
}
Δx = strtol(argv[1], &p, 0);
if(p == argv[1]){
fprint(2, "fnsize: invalid width\n");
return;
}
Δy = strtol(argv[2], &p, 0);
if(p == argv[1])
fprint(2, "fnsize: invalid height\n");
}
static void
fnfiles(int, char **)
{
Sym *s;
for(s=sym; s<sym+nsym; s++)
print("%s %s %s\n", s->iname, s->name, s->path);
}
static int
command(char *p)
{
struct{
char *name;
void (*fn)(int, char**);
} *cp, cmd[] = {
"f", fnfiles,
"s", fnsize,
"r", fnadd,
"w", fnwrite,
"d", fndisplay
};
int n;
char *f[16];
for(cp=cmd; cp<cmd+nelem(cmd); cp++){
n = strlen(cp->name);
if(strncmp(p, cp->name, n) == 0
&& (p[n] == 0 || isspace(p[n]))){
n = tokenize(p, f, nelem(f));
cp->fn(n, f);
return 1;
}
}
return 0;
}
static int
isbuiltin(char *p, int n)
{
char **fp, *fn[] = {
"X", "Y", "Z",
"x", "y", "z"
};
for(fp=fn; fp<fn+nelem(fn); fp++)
if(strncmp(p, *fp, n) == 0 && strlen(*fp) == n)
return 1;
return 0;
}
static int
mkcoords(char *s, char *e)
{
char *p, **cp, *c[2] = {nil};
while(isspace(*s))
s++;
for(p=s+1, cp=c; p<e; p++){
if(*p == ']'){
*p = 0;
break;
}else if(*p == ','){
if(cp >= c + nelem(c)){
fprint(2, "invalid index spec\n");
return -1;
}
*p = 0;
*cp++ = p + 1;
}
}
p = esmprint(", %s,%s,%s)", s+1,
c[0] != nil ? c[0] : "y",
c[1] != nil ? c[1] : "z");
newtok(p);
return 0;
}
static int
getcoords(char *s)
{
char *p;
for(p=s; *p!=']' && *p!=0; p++)
;
return *p == 0 ? -1 : p + 2 - s;
}
static int
peekrune(char *p, Rune ro)
{
Rune r;
while(isspace(*p))
p++;
chartorune(&r, p);
return r == ro;
}
static int
notaword(Rune r)
{
char *o, *op = "+-*/%?:^,&|<>=![], ()";
if(isdigitrune(r))
return 1;
for(o=op; o<op+strlen(op); o++)
if(r == *o)
return 1;
return 0;
}
static int
getname(char *s)
{
char *p, *q;
Rune r;
q = p = s + chartorune(&r, s);
while(r != 0 && !notaword(r) && !isspace(r)){
q = p;
p += chartorune(&r, p);
}
return q - s;
}
void
parse(char *s)
{
int n, m, nchar;
char *p, *new;
Rune r;
Sym *sp;
for(p=s, nchar=0, new=nil; *p != 0; p++){
if(isspace(*p))
continue;
if(nchar == 0 && command(p))
return;
if(*p == '#')
break;
nchar++;
n = chartorune(&r, p);
if(notaword(r))
goto next;
n = getname(p);
if(peekrune(p + n, '('))
goto next;
if(isbuiltin(p, n))
goto next;
if((sp = getsym(p, n)) == nil){
if(nchar > 1 || !peekrune(p + n, '=')){
s = emalloc(n + 1);
memcpy(s, p, n);
fprint(2, "unknown symbol %s\n", s);
free(s);
goto end;
}
new = emalloc(n + 1);
memcpy(new, p, n);
while(isspace(p[n]))
n++;
n++;
s = p + n;
goto next;
}
addtok(s, p - s);
sp->ref = 1;
newtok(estrdup("RIMAGE("));
newtok(estrdup(sp->cname));
s = p + n;
if(!peekrune(s, '[')){
newtok(estrdup(",x,y,z)"));
goto next;
}
if((m = getcoords(s)) < 0){
fprint(2, "syntax error: no matching ]\n");
goto end;
}
if(mkcoords(s, s + m - 1) < 0)
goto end;
s += m;
p += m - 1;
next:
p += n - 1;
}
if(nchar == 0)
return;
if(p > s)
addtok(s, p - s);
if((p = execute()) != nil){
sp = newsym(new);
sp->path = estrdup(p);
if(!quiet)
show(p);
}
end:
free(new);
cleanup();
}