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; 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 while(*p){ 342 m = strtoul(p, &p, 0); 343 switch(*p){ 344 case 0: 345 n = m; 346 break; 347 case 'y': 348 m *= 12; 349 /* fall through */ 350 case 'M': 351 m *= 30; 352 /* fall through */ 353 case 'd': 354 m *= 24; 355 /* fall through */ 356 case 'h': 357 m *= 60; 358 /* fall through */ 359 case 'm': 360 m *= 60; 361 /* fall through */ 362 case 's': 363 n += m; 364 p++; 365 break; 366 default: 367 synbad("bad time syntax, ", pin); 368 } 369 } 370 371 r = dir->mtime + n < time(0); 372 free(dir); 373 return r; 374 } 375 376 int 377 isolderthan(char *a, char *b) 378 { 379 int r; 380 Dir *ad, *bd; 381 382 ad = dirstat(a); 383 bd = dirstat(b); 384 if (ad == nil || bd == nil) 385 r = 0; 386 else 387 r = ad->mtime > bd->mtime; 388 free(ad); 389 free(bd); 390 return r; 391 } 392 393 int 394 isnewerthan(char *a, char *b) 395 { 396 int r; 397 Dir *ad, *bd; 398 399 ad = dirstat(a); 400 bd = dirstat(b); 401 if (ad == nil || bd == nil) 402 r = 0; 403 else 404 r = ad->mtime < bd->mtime; 405 free(ad); 406 free(bd); 407 return r; 408 } 409