shithub: purgatorio

ref: f8935b5778397074d41a48205e5c7f87d7b531fe
dir: /appl/cmd/test.b/

View raw version
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();
}