Blob
1 /*2 * POSIX standard3 * test expression4 * [ expression ]5 *6 * Plan 9 additions:7 * -A file exists and is append-only8 * -L file exists and is exclusive-use9 * -T file exists and is temporary10 */12 #include <u.h>13 #include <libc.h>15 #define isatty plan9_isatty17 #define EQ(a,b) ((tmp=a)==0?0:(strcmp(tmp,b)==0))19 int ap;20 int ac;21 char **av;22 char *tmp;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);38 void39 main(int argc, char *argv[])40 {41 int r;42 char *c;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 have55 * 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 }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 }75 int76 nxtintarg(int *pans)77 {78 if(ap<ac && isint(av[ap], pans)){79 ap++;80 return 1;81 }82 return 0;83 }85 int86 e(void)87 {88 int p1;90 p1 = e1();91 if (EQ(nxtarg(1), "-o"))92 return(p1 || e());93 ap--;94 return(p1);95 }97 int98 e1(void)99 {100 int p1;102 p1 = e2();103 if (EQ(nxtarg(1), "-a"))104 return (p1 && e1());105 ap--;106 return(p1);107 }109 int110 e2(void)111 {112 if (EQ(nxtarg(0), "!"))113 return(!e2());114 ap--;115 return(e3());116 }118 int119 e3(void)120 {121 int p1, int1, int2;122 char *a, *p2;124 a = nxtarg(0);125 if(EQ(a, "(")) {126 p1 = e();127 if(!EQ(nxtarg(0), ")"))128 synbad(") expected","");129 return(p1);130 }132 if(EQ(a, "-A"))133 return(hasmode(nxtarg(0), DMAPPEND));135 if(EQ(a, "-L"))136 return(hasmode(nxtarg(0), DMEXCL));138 if(EQ(a, "-T"))139 return(hasmode(nxtarg(0), DMTMP));141 if(EQ(a, "-f"))142 return(isreg(nxtarg(0)));144 if(EQ(a, "-d"))145 return(isdir(nxtarg(0)));147 if(EQ(a, "-r"))148 return(tio(nxtarg(0), 4));150 if(EQ(a, "-w"))151 return(tio(nxtarg(0), 2));153 if(EQ(a, "-x"))154 return(tio(nxtarg(0), 1));156 if(EQ(a, "-e"))157 return(tio(nxtarg(0), 0));159 if(EQ(a, "-c"))160 return(0);162 if(EQ(a, "-b"))163 return(0);165 if(EQ(a, "-u"))166 return(0);168 if(EQ(a, "-g"))169 return(0);171 if(EQ(a, "-s"))172 return(fsizep(nxtarg(0)));174 if(EQ(a, "-t"))175 if(ap>=ac)176 return(isatty(1));177 else if(nxtintarg(&int1))178 return(isatty(int1));179 else180 synbad("not a valid file descriptor number ", "");182 if(EQ(a, "-n"))183 return(!EQ(nxtarg(0), ""));184 if(EQ(a, "-z"))185 return(EQ(nxtarg(0), ""));187 p2 = nxtarg(1);188 if (p2==0)189 return(!EQ(a,""));190 if(EQ(p2, "="))191 return(EQ(nxtarg(0), a));193 if(EQ(p2, "!="))194 return(!EQ(nxtarg(0), a));196 if(EQ(p2, "-older"))197 return(isolder(nxtarg(0), a));199 if(EQ(p2, "-ot"))200 return(isolderthan(nxtarg(0), a));202 if(EQ(p2, "-nt"))203 return(isnewerthan(nxtarg(0), a));205 if(!isint(a, &int1))206 synbad("unexpected operator/operand: ", p2);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 }223 synbad("unknown operator ",p2);224 return 0; /* to shut ken up */225 }227 int228 tio(char *a, int f)229 {230 return access (a, f) >= 0;231 }233 /* copy to local memory; clear names for safety */234 int235 localstat(char *f, Dir *dir)236 {237 Dir *d;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 }251 /* copy to local memory; clear names for safety */252 int253 localfstat(int f, Dir *dir)254 {255 Dir *d;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 }269 int270 hasmode(char *f, ulong m)271 {272 Dir dir;274 if(localstat(f,&dir)<0)275 return(0);276 return(dir.mode&m);277 }279 int280 isdir(char *f)281 {282 Dir dir;284 if(localstat(f,&dir)<0)285 return(0);286 return(dir.mode&DMDIR);287 }289 int290 isreg(char *f)291 {292 Dir dir;294 if(localstat(f,&dir)<0)295 return(0);296 return(!(dir.mode&DMDIR));297 }299 int300 isatty(int fd)301 {302 Dir d1, d2;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 }311 int312 fsizep(char *f)313 {314 Dir dir;316 if(localstat(f,&dir)<0)317 return(0);318 return(dir.length>0);319 }321 void322 synbad(char *s1, char *s2)323 {324 int len;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 }335 int336 isint(char *s, int *pans)337 {338 char *ep;340 *pans = strtol(s, &ep, 0);341 return (*ep == 0);342 }344 int345 isolder(char *pin, char *f)346 {347 char *p = pin;348 ulong n, m;349 Dir dir;351 if(localstat(f,&dir)<0)352 return(0);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 }386 return(dir.mtime+n < time(0));387 }389 int390 isolderthan(char *a, char *b)391 {392 Dir ad, bd;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 }401 int402 isnewerthan(char *a, char *b)403 {404 Dir ad, bd;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 }