1 /* 2 * POSIX standard 3 * test expression 4 * [ expression ] 5 * 6 * Plan 9 additions: 7 * -A file exists and is append-only 8 * -L file exists and is exclusive-use 9 * -T file exists and is temporary 10 */ 11 12 #include <u.h> 13 #include <libc.h> 14 15 #define EQ(a,b) ((tmp=a)==0?0:(strcmp(tmp,b)==0)) 16 17 int ap; 18 int ac; 19 char **av; 20 char *tmp; 21 22 void synbad(char *, char *); 23 int fsizep(char *); 24 int isdir(char *); 25 int isreg(char *); 26 int isatty(int); 27 int isint(char *, int *); 28 int isolder(char *, char *); 29 int isolderthan(char *, char *); 30 int isnewerthan(char *, char *); 31 int hasmode(char *, ulong); 32 int tio(char *, int); 33 int e(void), e1(void), e2(void), e3(void); 34 char *nxtarg(int); 35 36 void 37 main(int argc, char *argv[]) 38 { 39 int r; 40 char *c; 41 42 ac = argc; av = argv; ap = 1; 43 if(EQ(argv[0],"[")) { 44 if(!EQ(argv[--ac],"]")) 45 synbad("] missing",""); 46 } 47 argv[ac] = 0; 48 if (ac<=1) 49 exits("usage"); 50 r = e(); 51 /* 52 * nice idea but short-circuit -o and -a operators may have 53 * not consumed their right-hand sides. 54 */ 55 if(0 && (c = nxtarg(1)) != nil) 56 synbad("unexpected operator/operand: ", c); 57 exits(r?0:"false"); 58 } 59 60 char * 61 nxtarg(int mt) 62 { 63 if(ap>=ac){ 64 if(mt){ 65 ap++; 66 return(0); 67 } 68 synbad("argument expected",""); 69 } 70 return(av[ap++]); 71 } 72 73 int 74 nxtintarg(int *pans) 75 { 76 if(ap<ac && isint(av[ap], pans)){ 77 ap++; 78 return 1; 79 } 80 return 0; 81 } 82 83 int 84 e(void) 85 { 86 int p1; 87 88 p1 = e1(); 89 if (EQ(nxtarg(1), "-o")) 90 return(p1 || e()); 91 ap--; 92 return(p1); 93 } 94 95 int 96 e1(void) 97 { 98 int p1; 99 100 p1 = e2(); 101 if (EQ(nxtarg(1), "-a")) 102 return (p1 && e1()); 103 ap--; 104 return(p1); 105 } 106 107 int 108 e2(void) 109 { 110 if (EQ(nxtarg(0), "!")) 111 return(!e2()); 112 ap--; 113 return(e3()); 114 } 115 116 int 117 e3(void) 118 { 119 int p1, int1, int2; 120 char *a, *p2; 121 122 a = nxtarg(0); 123 if(EQ(a, "(")) { 124 p1 = e(); 125 if(!EQ(nxtarg(0), ")")) 126 synbad(") expected",""); 127 return(p1); 128 } 129 130 if(EQ(a, "-A")) 131 return(hasmode(nxtarg(0), DMAPPEND)); 132 133 if(EQ(a, "-L")) 134 return(hasmode(nxtarg(0), DMEXCL)); 135 136 if(EQ(a, "-T")) 137 return(hasmode(nxtarg(0), DMTMP)); 138 139 if(EQ(a, "-f")) 140 return(isreg(nxtarg(0))); 141 142 if(EQ(a, "-d")) 143 return(isdir(nxtarg(0))); 144 145 if(EQ(a, "-r")) 146 return(tio(nxtarg(0), 4)); 147 148 if(EQ(a, "-w")) 149 return(tio(nxtarg(0), 2)); 150 151 if(EQ(a, "-x")) 152 return(tio(nxtarg(0), 1)); 153 154 if(EQ(a, "-e")) 155 return(tio(nxtarg(0), 0)); 156 157 if(EQ(a, "-c")) 158 return(0); 159 160 if(EQ(a, "-b")) 161 return(0); 162 163 if(EQ(a, "-u")) 164 return(0); 165 166 if(EQ(a, "-g")) 167 return(0); 168 169 if(EQ(a, "-s")) 170 return(fsizep(nxtarg(0))); 171 172 if(EQ(a, "-t")) 173 if(ap>=ac) 174 return(isatty(1)); 175 else if(nxtintarg(&int1)) 176 return(isatty(int1)); 177 else 178 synbad("not a valid file descriptor number ", ""); 179 180 if(EQ(a, "-n")) 181 return(!EQ(nxtarg(0), "")); 182 if(EQ(a, "-z")) 183 return(EQ(nxtarg(0), "")); 184 185 p2 = nxtarg(1); 186 if (p2==0) 187 return(!EQ(a,"")); 188 if(EQ(p2, "=")) 189 return(EQ(nxtarg(0), a)); 190 191 if(EQ(p2, "!=")) 192 return(!EQ(nxtarg(0), a)); 193 194 if(EQ(p2, "-older")) 195 return(isolder(nxtarg(0), a)); 196 197 if(EQ(p2, "-ot")) 198 return(isolderthan(nxtarg(0), a)); 199 200 if(EQ(p2, "-nt")) 201 return(isnewerthan(nxtarg(0), a)); 202 203 if(!isint(a, &int1)) 204 synbad("unexpected operator/operand: ", p2); 205 206 if(nxtintarg(&int2)){ 207 if(EQ(p2, "-eq")) 208 return(int1==int2); 209 if(EQ(p2, "-ne")) 210 return(int1!=int2); 211 if(EQ(p2, "-gt")) 212 return(int1>int2); 213 if(EQ(p2, "-lt")) 214 return(int1<int2); 215 if(EQ(p2, "-ge")) 216 return(int1>=int2); 217 if(EQ(p2, "-le")) 218 return(int1<=int2); 219 } 220 221 synbad("unknown operator ",p2); 222 return 0; /* to shut ken up */ 223 } 224 225 int 226 tio(char *a, int f) 227 { 228 return access (a, f) >= 0; 229 } 230 231 /* 232 * note that the name strings pointed to by Dir members are 233 * allocated with the Dir itself (by the same call to malloc), 234 * but are not included in sizeof(Dir), so copying a Dir won't 235 * copy the strings it points to. 236 */ 237 238 int 239 hasmode(char *f, ulong m) 240 { 241 int r; 242 Dir *dir; 243 244 dir = dirstat(f); 245 if (dir == nil) 246 return 0; 247 r = (dir->mode & m) != 0; 248 free(dir); 249 return r; 250 } 251 252 int 253 isdir(char *f) 254 { 255 return hasmode(f, DMDIR); 256 } 257 258 int 259 isreg(char *f) 260 { 261 int r; 262 Dir *dir; 263 264 dir = dirstat(f); 265 if (dir == nil) 266 return 0; 267 r = (dir->mode & DMDIR) == 0; 268 free(dir); 269 return r; 270 } 271 272 int 273 isatty(int fd) 274 { 275 int r; 276 Dir *d1, *d2; 277 278 d1 = dirfstat(fd); 279 d2 = dirstat("/dev/cons"); 280 if (d1 == nil || d2 == nil) 281 r = 0; 282 else 283 r = d1->type == d2->type && d1->dev == d2->dev && 284 d1->qid.path == d2->qid.path; 285 free(d1); 286 free(d2); 287 return r; 288 } 289 290 int 291 fsizep(char *f) 292 { 293 int r; 294 Dir *dir; 295 296 dir = dirstat(f); 297 if (dir == nil) 298 return 0; 299 r = dir->length > 0; 300 free(dir); 301 return r; 302 } 303 304 void 305 synbad(char *s1, char *s2) 306 { 307 int len; 308 309 write(2, "test: ", 6); 310 if ((len = strlen(s1)) != 0) 311 write(2, s1, len); 312 if ((len = strlen(s2)) != 0) 313 write(2, s2, len); 314 write(2, "\n", 1); 315 exits("bad syntax"); 316 } 317 318 int 319 isint(char *s, int *pans) 320 { 321 char *ep; 322 323 *pans = strtol(s, &ep, 0); 324 return (*ep == 0); 325 } 326 327 int 328 isolder(char *pin, char *f) 329 { 330 int r, rel; 331 ulong n, m; 332 char *p = pin; 333 Dir *dir; 334 335 dir = dirstat(f); 336 if (dir == nil) 337 return 0; 338 339 /* parse time */ 340 n = 0; 341 rel = 0; 342 while(*p){ 343 m = strtoul(p, &p, 0); 344 switch(*p){ 345 case 0: 346 n = m; 347 break; 348 case 'y': 349 m *= 12; 350 /* fall through */ 351 case 'M': 352 m *= 30; 353 /* fall through */ 354 case 'd': 355 m *= 24; 356 /* fall through */ 357 case 'h': 358 m *= 60; 359 /* fall through */ 360 case 'm': 361 m *= 60; 362 /* fall through */ 363 case 's': 364 n += m; 365 p++; 366 rel = 1; 367 break; 368 default: 369 synbad("bad time syntax, ", pin); 370 } 371 } 372 if (!rel) 373 m = n; 374 else{ 375 m = time(0); 376 if (n > m) /* before epoch? */ 377 m = 0; 378 else 379 m -= n; 380 } 381 r = dir->mtime < m; 382 free(dir); 383 return r; 384 } 385 386 int 387 isolderthan(char *a, char *b) 388 { 389 int r; 390 Dir *ad, *bd; 391 392 ad = dirstat(a); 393 bd = dirstat(b); 394 if (ad == nil || bd == nil) 395 r = 0; 396 else 397 r = ad->mtime > bd->mtime; 398 free(ad); 399 free(bd); 400 return r; 401 } 402 403 int 404 isnewerthan(char *a, char *b) 405 { 406 int r; 407 Dir *ad, *bd; 408 409 ad = dirstat(a); 410 bd = dirstat(b); 411 if (ad == nil || bd == nil) 412 r = 0; 413 else 414 r = ad->mtime < bd->mtime; 415 free(ad); 416 free(bd); 417 return r; 418 } 419