1implement Test; 2 3# 4# venerable 5# test expression 6# 7 8include "sys.m"; 9 sys: Sys; 10 stderr: ref Sys->FD; 11 12include "draw.m"; 13 14include "daytime.m"; 15 daytime: Daytime; 16 17Test: module 18{ 19 init: fn(ctxt: ref Draw->Context, argv: list of string); 20}; 21 22gargs: list of string; 23 24init(nil: ref Draw->Context, args: list of string) 25{ 26 if(args == nil) 27 return; 28 gargs = tl args; 29 30 sys = load Sys Sys->PATH; 31 stderr = sys->fildes(2); 32 33 if(gargs == nil) 34 raise "fail:usage"; 35 if(!e()) 36 raise "fail:false"; 37} 38 39nextarg(mt: int): string 40{ 41 if(gargs == nil){ 42 if(mt) 43 return nil; 44 synbad("argument expected"); 45 } 46 s := hd gargs; 47 gargs = tl gargs; 48 return s; 49} 50 51nextintarg(): (int, int) 52{ 53 if(gargs != nil && isint(hd gargs)) 54 return (1, int nextarg(0)); 55 return (0, 0); 56} 57 58isnextarg(s: string): int 59{ 60 if(gargs != nil && hd gargs == s){ 61 gargs = tl gargs; 62 return 1; 63 } 64 return 0; 65} 66 67e(): int 68{ 69 p1 := e1(); 70 if(isnextarg("-o")) 71 return p1 || e(); 72 return p1; 73} 74 75e1(): int 76{ 77 p1 := e2(); 78 if(isnextarg("-a")) 79 return p1 && e1(); 80 return p1; 81} 82 83e2(): int 84{ 85 if(isnextarg("!")) 86 return !e2(); 87 return e3(); 88} 89 90e3(): int 91{ 92 a := nextarg(0); 93 case a { 94 "(" => 95 p1 := e(); 96 if(nextarg(0) != ")") 97 synbad(") expected"); 98 return p1; 99 "-A" => 100 return hasmode(nextarg(0), Sys->DMAPPEND); 101 "-L" => 102 return hasmode(nextarg(0), Sys->DMEXCL); 103 "-T" => 104 return hasmode(nextarg(0), Sys->DMTMP); 105 "-f" => 106 f := nextarg(0); 107 return exists(f) && !hasmode(f, Sys->DMDIR); 108 "-d" => 109 return hasmode(nextarg(0), Sys->DMDIR); 110 "-r" => 111 return sys->open(nextarg(0), Sys->OREAD) != nil; 112 "-w" => 113 return sys->open(nextarg(0), Sys->OWRITE) != nil; 114 "-x" => 115 fd := sys->open(nextarg(0), Sys->OREAD); 116 if(fd == nil) 117 return 0; 118 (ok, d) := sys->fstat(fd); 119 if(ok < 0) 120 return 0; 121 return (d.mode & 8r111) != 0; 122 "-e" => 123 return exists(nextarg(0)); 124 "-s" => 125 (ok, d) := sys->stat(nextarg(0)); 126 if(ok < 0) 127 return 0; 128 return d.length > big 0; 129 "-t" => 130 (ok, fd) := nextintarg(); 131 if(!ok) 132 return iscons(1); 133 return iscons(fd); 134 "-n" => 135 return nextarg(0) != ""; 136 "-z" => 137 return nextarg(0) == ""; 138 * => 139 p2 := nextarg(1); 140 if(p2 == nil) 141 return a != nil; 142 case p2 { 143 "=" => 144 return nextarg(0) == a; 145 "!=" => 146 return nextarg(0) != a; 147 "-older" => 148 return isolder(nextarg(0), a); 149 "-ot" => 150 return isolderthan(a, nextarg(0)); 151 "-nt" => 152 return isnewerthan(a, nextarg(0)); 153 } 154 155 if(!isint(a)) 156 return a != nil; 157 158 int1 := int a; 159 (ok, int2) := nextintarg(); 160 if(ok){ 161 case p2 { 162 "-eq" => 163 return int1 == int2; 164 "-ne" => 165 return int1 != int2; 166 "-gt" => 167 return int1 > int2; 168 "-lt" => 169 return int1 < int2; 170 "-ge" => 171 return int1 >= int2; 172 "-le" => 173 return int1 <= int2; 174 } 175 } 176 177 synbad("unknown operator " + p2); 178 return 0; 179 } 180} 181 182synbad(s: string) 183{ 184 sys->fprint(stderr, "test: bad syntax: %s\n", s); 185 raise "fail:bad syntax"; 186} 187 188isint(s: string): int 189{ 190 if(s == nil) 191 return 0; 192 for(i := 0; i < len s; i++) 193 if(s[i] < '0' || s[i] > '9') 194 return 0; 195 return 1; 196} 197 198exists(f: string): int 199{ 200 return sys->stat(f).t0 >= 0; 201} 202 203hasmode(f: string, m: int): int 204{ 205 (ok, d) := sys->stat(f); 206 if(ok < 0) 207 return 0; 208 return (d.mode & m) != 0; 209} 210 211iscons(fno: int): int 212{ 213 fd := sys->fildes(fno); 214 if(fd == nil) 215 return 0; 216 s := sys->fd2path(fd); 217 n := len "/dev/cons"; 218 return s == "#c/cons" || len s >= n && s[len s-n:] == "/dev/cons"; 219} 220 221isolder(t: string, f: string): int 222{ 223 (ok, dir) := sys->stat(f); 224 if(ok < 0) 225 return 0; 226 227 n := 0; 228 for(i := 0; i < len t;){ 229 for(j := i; j < len t; j++) 230 if(!(t[j] >= '0' && t[j] <= '9')) 231 break; 232 if(i == j) 233 synbad("bad time syntax, "+t); 234 m := int t[i:j]; 235 i = j; 236 if(i == len t){ 237 n = m; 238 break; 239 } 240 case t[i++] { 241 'y' => n += m*12*30*24*3600; 242 'M' => n += m*30*24*3600; 243 'd' => n += m*24*3600; 244 'h' => n += m*3600; 245 'm' => n += m*60; 246 's' => n += m; 247 * => synbad("bad time syntax, "+t); 248 } 249 } 250 251 return dir.mtime+n < now(); 252} 253 254isolderthan(a: string, b: string): int 255{ 256 (aok, ad) := sys->stat(a); 257 if(aok < 0) 258 return 0; 259 (bok, bd) := sys->stat(b); 260 if(bok < 0) 261 return 0; 262 return ad.mtime < bd.mtime; 263} 264 265isnewerthan(a: string, b: string): int 266{ 267 (aok, ad) := sys->stat(a); 268 if(aok < 0) 269 return 0; 270 (bok, bd) := sys->stat(b); 271 if(bok < 0) 272 return 0; 273 return ad.mtime > bd.mtime; 274} 275 276now(): int 277{ 278 if(daytime == nil){ 279 daytime = load Daytime Daytime->PATH; 280 if(daytime == nil) 281 synbad(sys->sprint("can't load %s: %r", Daytime->PATH)); 282 } 283 return daytime->now(); 284} 285