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