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