implement Test; ## venerable# test expression# include "sys.m"; sys: Sys; stderr: ref Sys->FD; include "draw.m"; include "daytime.m"; daytime: Daytime; Test: module{ init: fn(ctxt: ref Draw->Context, argv: list of string);}; gargs: list of string; init(nil: ref Draw->Context, args: list of string){ if(args == nil) return; gargs = tl args; sys = load Sys Sys->PATH; stderr = sys->fildes(2); if(gargs == nil) raise "fail:usage"; if(!e()) raise "fail:false";} nextarg(mt: int): string{ if(gargs == nil){ if(mt) return nil; synbad("argument expected"); } s := hd gargs; gargs = tl gargs; return s;} nextintarg(): (int, int){ if(gargs != nil && isint(hd gargs)) return (1, int nextarg(0)); return (0, 0);} isnextarg(s: string): int{ if(gargs != nil && hd gargs == s){ gargs = tl gargs; return 1; } return 0;} e(): int{ p1 := e1(); if(isnextarg("-o")) return p1 || e(); return p1;} e1(): int{ p1 := e2(); if(isnextarg("-a")) return p1 && e1(); return p1;} e2(): int{ if(isnextarg("!")) return !e2(); return e3();} e3(): int{ a := nextarg(0); case a { "(" => p1 := e(); if(nextarg(0) != ")") synbad(") expected"); return p1; "-A" => return hasmode(nextarg(0), Sys->DMAPPEND); "-L" => return hasmode(nextarg(0), Sys->DMEXCL); "-T" => return hasmode(nextarg(0), Sys->DMTMP); "-f" => f := nextarg(0); return exists(f) && !hasmode(f, Sys->DMDIR); "-d" => return hasmode(nextarg(0), Sys->DMDIR); "-r" => return sys->open(nextarg(0), Sys->OREAD) != nil; "-w" => return sys->open(nextarg(0), Sys->OWRITE) != nil; "-x" => fd := sys->open(nextarg(0), Sys->OREAD); if(fd == nil) return 0; (ok, d) := sys->fstat(fd); if(ok < 0) return 0; return (d.mode & 8r111) != 0; "-e" => return exists(nextarg(0)); "-s" => (ok, d) := sys->stat(nextarg(0)); if(ok < 0) return 0; return d.length > big 0; "-t" => (ok, fd) := nextintarg(); if(!ok) return iscons(1); return iscons(fd); "-n" => return nextarg(0) != ""; "-z" => return nextarg(0) == ""; * => p2 := nextarg(1); if(p2 == nil) return a != nil; case p2 { "=" => return nextarg(0) == a; "!=" => return nextarg(0) != a; "-older" => return isolder(nextarg(0), a); "-ot" => return isolderthan(a, nextarg(0)); "-nt" => return isnewerthan(a, nextarg(0)); } if(!isint(a)) return a != nil; int1 := int a; (ok, int2) := nextintarg(); if(ok){ case p2 { "-eq" => return int1 == int2; "-ne" => return int1 != int2; "-gt" => return int1 > int2; "-lt" => return int1 < int2; "-ge" => return int1 >= int2; "-le" => return int1 <= int2; } } synbad("unknown operator " + p2); return 0; }} synbad(s: string){ sys->fprint(stderr, "test: bad syntax: %s\n", s); raise "fail:bad syntax";} isint(s: string): int{ if(s == nil) return 0; for(i := 0; i < len s; i++) if(s[i] < '0' || s[i] > '9') return 0; return 1;} exists(f: string): int{ return sys->stat(f).t0 >= 0;} hasmode(f: string, m: int): int{ (ok, d) := sys->stat(f); if(ok < 0) return 0; return (d.mode & m) != 0;} iscons(fno: int): int{ fd := sys->fildes(fno); if(fd == nil) return 0; s := sys->fd2path(fd); n := len "/dev/cons"; return s == "#c/cons" || len s >= n && s[len s-n:] == "/dev/cons";} isolder(t: string, f: string): int{ (ok, dir) := sys->stat(f); if(ok < 0) return 0; n := 0; for(i := 0; i < len t;){ for(j := i; j < len t; j++) if(!(t[j] >= '0' && t[j] <= '9')) break; if(i == j) synbad("bad time syntax, "+t); m := int t[i:j]; i = j; if(i == len t){ n = m; break; } case t[i++] { 'y' => n += m*12*30*24*3600; 'M' => n += m*30*24*3600; 'd' => n += m*24*3600; 'h' => n += m*3600; 'm' => n += m*60; 's' => n += m; * => synbad("bad time syntax, "+t); } } return dir.mtime+n < now();} isolderthan(a: string, b: string): int{ (aok, ad) := sys->stat(a); if(aok < 0) return 0; (bok, bd) := sys->stat(b); if(bok < 0) return 0; return ad.mtime < bd.mtime;} isnewerthan(a: string, b: string): int{ (aok, ad) := sys->stat(a); if(aok < 0) return 0; (bok, bd) := sys->stat(b); if(bok < 0) return 0; return ad.mtime > bd.mtime;} now(): int{ if(daytime == nil){ daytime = load Daytime Daytime->PATH; if(daytime == nil) synbad(sys->sprint("can't load %s: %r", Daytime->PATH)); } return daytime->now();}
implement Test;
#
# venerable
# test expression
#
include "sys.m";
sys: Sys;
stderr: ref Sys->FD;
include "draw.m";
include "daytime.m";
daytime: Daytime;
Test: module
{
init: fn(ctxt: ref Draw->Context, argv: list of string);
};
gargs: list of string;
init(nil: ref Draw->Context, args: list of string)
{
if(args == nil)
return;
gargs = tl args;
sys = load Sys Sys->PATH;
stderr = sys->fildes(2);
if(gargs == nil)
raise "fail:usage";
if(!e())
raise "fail:false";
}
nextarg(mt: int): string
{
if(gargs == nil){
if(mt)
return nil;
synbad("argument expected");
}
s := hd gargs;
gargs = tl gargs;
return s;
}
nextintarg(): (int, int)
{
if(gargs != nil && isint(hd gargs))
return (1, int nextarg(0));
return (0, 0);
}
isnextarg(s: string): int
{
if(gargs != nil && hd gargs == s){
gargs = tl gargs;
return 1;
}
return 0;
}
e(): int
{
p1 := e1();
if(isnextarg("-o"))
return p1 || e();
return p1;
}
e1(): int
{
p1 := e2();
if(isnextarg("-a"))
return p1 && e1();
return p1;
}
e2(): int
{
if(isnextarg("!"))
return !e2();
return e3();
}
e3(): int
{
a := nextarg(0);
case a {
"(" =>
p1 := e();
if(nextarg(0) != ")")
synbad(") expected");
return p1;
"-A" =>
return hasmode(nextarg(0), Sys->DMAPPEND);
"-L" =>
return hasmode(nextarg(0), Sys->DMEXCL);
"-T" =>
return hasmode(nextarg(0), Sys->DMTMP);
"-f" =>
f := nextarg(0);
return exists(f) && !hasmode(f, Sys->DMDIR);
"-d" =>
return hasmode(nextarg(0), Sys->DMDIR);
"-r" =>
return sys->open(nextarg(0), Sys->OREAD) != nil;
"-w" =>
return sys->open(nextarg(0), Sys->OWRITE) != nil;
"-x" =>
fd := sys->open(nextarg(0), Sys->OREAD);
if(fd == nil)
return 0;
(ok, d) := sys->fstat(fd);
if(ok < 0)
return 0;
return (d.mode & 8r111) != 0;
"-e" =>
return exists(nextarg(0));
"-s" =>
(ok, d) := sys->stat(nextarg(0));
if(ok < 0)
return 0;
return d.length > big 0;
"-t" =>
(ok, fd) := nextintarg();
if(!ok)
return iscons(1);
return iscons(fd);
"-n" =>
return nextarg(0) != "";
"-z" =>
return nextarg(0) == "";
* =>
p2 := nextarg(1);
if(p2 == nil)
return a != nil;
case p2 {
"=" =>
return nextarg(0) == a;
"!=" =>
return nextarg(0) != a;
"-older" =>
return isolder(nextarg(0), a);
"-ot" =>
return isolderthan(a, nextarg(0));
"-nt" =>
return isnewerthan(a, nextarg(0));
}
if(!isint(a))
return a != nil;
int1 := int a;
(ok, int2) := nextintarg();
if(ok){
case p2 {
"-eq" =>
return int1 == int2;
"-ne" =>
return int1 != int2;
"-gt" =>
return int1 > int2;
"-lt" =>
return int1 < int2;
"-ge" =>
return int1 >= int2;
"-le" =>
return int1 <= int2;
}
}
synbad("unknown operator " + p2);
return 0;
}
}
synbad(s: string)
{
sys->fprint(stderr, "test: bad syntax: %s\n", s);
raise "fail:bad syntax";
}
isint(s: string): int
{
if(s == nil)
return 0;
for(i := 0; i < len s; i++)
if(s[i] < '0' || s[i] > '9')
return 0;
return 1;
}
exists(f: string): int
{
return sys->stat(f).t0 >= 0;
}
hasmode(f: string, m: int): int
{
(ok, d) := sys->stat(f);
if(ok < 0)
return 0;
return (d.mode & m) != 0;
}
iscons(fno: int): int
{
fd := sys->fildes(fno);
if(fd == nil)
return 0;
s := sys->fd2path(fd);
n := len "/dev/cons";
return s == "#c/cons" || len s >= n && s[len s-n:] == "/dev/cons";
}
isolder(t: string, f: string): int
{
(ok, dir) := sys->stat(f);
if(ok < 0)
return 0;
n := 0;
for(i := 0; i < len t;){
for(j := i; j < len t; j++)
if(!(t[j] >= '0' && t[j] <= '9'))
break;
if(i == j)
synbad("bad time syntax, "+t);
m := int t[i:j];
i = j;
if(i == len t){
n = m;
break;
}
case t[i++] {
'y' => n += m*12*30*24*3600;
'M' => n += m*30*24*3600;
'd' => n += m*24*3600;
'h' => n += m*3600;
'm' => n += m*60;
's' => n += m;
* => synbad("bad time syntax, "+t);
}
}
return dir.mtime+n < now();
}
isolderthan(a: string, b: string): int
{
(aok, ad) := sys->stat(a);
if(aok < 0)
return 0;
(bok, bd) := sys->stat(b);
if(bok < 0)
return 0;
return ad.mtime < bd.mtime;
}
isnewerthan(a: string, b: string): int
{
(aok, ad) := sys->stat(a);
if(aok < 0)
return 0;
(bok, bd) := sys->stat(b);
if(bok < 0)
return 0;
return ad.mtime > bd.mtime;
}
now(): int
{
if(daytime == nil){
daytime = load Daytime Daytime->PATH;
if(daytime == nil)
synbad(sys->sprint("can't load %s: %r", Daytime->PATH));
}
return daytime->now();
}