test.c (5783B)
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 /* copy to local memory; clear names for safety */ 234 int 235 localstat(char *f, Dir *dir) 236 { 237 Dir *d; 238 239 d = dirstat(f); 240 if(d == nil) 241 return(-1); 242 *dir = *d; 243 free(d); 244 dir->name = 0; 245 dir->uid = 0; 246 dir->gid = 0; 247 dir->muid = 0; 248 return 0; 249 } 250 251 /* copy to local memory; clear names for safety */ 252 int 253 localfstat(int f, Dir *dir) 254 { 255 Dir *d; 256 257 d = dirfstat(f); 258 if(d == nil) 259 return(-1); 260 *dir = *d; 261 free(d); 262 dir->name = 0; 263 dir->uid = 0; 264 dir->gid = 0; 265 dir->muid = 0; 266 return 0; 267 } 268 269 int 270 hasmode(char *f, ulong m) 271 { 272 Dir dir; 273 274 if(localstat(f,&dir)<0) 275 return(0); 276 return(dir.mode&m); 277 } 278 279 int 280 isdir(char *f) 281 { 282 Dir dir; 283 284 if(localstat(f,&dir)<0) 285 return(0); 286 return(dir.mode&DMDIR); 287 } 288 289 int 290 isreg(char *f) 291 { 292 Dir dir; 293 294 if(localstat(f,&dir)<0) 295 return(0); 296 return(!(dir.mode&DMDIR)); 297 } 298 299 int 300 isatty(int fd) 301 { 302 Dir d1, d2; 303 304 if(localfstat(fd, &d1) < 0) 305 return 0; 306 if(localstat("/dev/cons", &d2) < 0) 307 return 0; 308 return d1.type==d2.type && d1.dev==d2.dev && d1.qid.path==d2.qid.path; 309 } 310 311 int 312 fsizep(char *f) 313 { 314 Dir dir; 315 316 if(localstat(f,&dir)<0) 317 return(0); 318 return(dir.length>0); 319 } 320 321 void 322 synbad(char *s1, char *s2) 323 { 324 int len; 325 326 write(2, "test: ", 6); 327 if ((len = strlen(s1)) != 0) 328 write(2, s1, len); 329 if ((len = strlen(s2)) != 0) 330 write(2, s2, len); 331 write(2, "\n", 1); 332 exits("bad syntax"); 333 } 334 335 int 336 isint(char *s, int *pans) 337 { 338 char *ep; 339 340 *pans = strtol(s, &ep, 0); 341 return (*ep == 0); 342 } 343 344 int 345 isolder(char *pin, char *f) 346 { 347 char *p = pin; 348 ulong n, m; 349 Dir dir; 350 351 if(localstat(f,&dir)<0) 352 return(0); 353 354 /* parse time */ 355 n = 0; 356 while(*p){ 357 m = strtoul(p, &p, 0); 358 switch(*p){ 359 case 0: 360 n = m; 361 break; 362 case 'y': 363 m *= 12; 364 /* fall through */ 365 case 'M': 366 m *= 30; 367 /* fall through */ 368 case 'd': 369 m *= 24; 370 /* fall through */ 371 case 'h': 372 m *= 60; 373 /* fall through */ 374 case 'm': 375 m *= 60; 376 /* fall through */ 377 case 's': 378 n += m; 379 p++; 380 break; 381 default: 382 synbad("bad time syntax, ", pin); 383 } 384 } 385 386 return(dir.mtime+n < time(0)); 387 } 388 389 int 390 isolderthan(char *a, char *b) 391 { 392 Dir ad, bd; 393 394 if(localstat(a, &ad)<0) 395 return(0); 396 if(localstat(b, &bd)<0) 397 return(0); 398 return ad.mtime > bd.mtime; 399 } 400 401 int 402 isnewerthan(char *a, char *b) 403 { 404 Dir ad, bd; 405 406 if(localstat(a, &ad)<0) 407 return(0); 408 if(localstat(b, &bd)<0) 409 return(0); 410 return ad.mtime < bd.mtime; 411 }