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