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 /*234 * note that the name strings pointed to by Dir members are235 * allocated with the Dir itself (by the same call to malloc),236 * but are not included in sizeof(Dir), so copying a Dir won't237 * copy the strings it points to.238 */240 int241 hasmode(char *f, ulong m)242 {243 int r;244 Dir *dir;246 dir = dirstat(f);247 if (dir == nil)248 return 0;249 r = (dir->mode & m) != 0;250 free(dir);251 return r;252 }254 int255 isdir(char *f)256 {257 return hasmode(f, DMDIR);258 }260 int261 isreg(char *f)262 {263 int r;264 Dir *dir;266 dir = dirstat(f);267 if (dir == nil)268 return 0;269 r = (dir->mode & DMDIR) == 0;270 free(dir);271 return r;272 }274 int275 isatty(int fd)276 {277 int r;278 Dir *d1, *d2;280 d1 = dirfstat(fd);281 d2 = dirstat("/dev/cons");282 if (d1 == nil || d2 == nil)283 r = 0;284 else285 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 }292 int293 fsizep(char *f)294 {295 int r;296 Dir *dir;298 dir = dirstat(f);299 if (dir == nil)300 return 0;301 r = dir->length > 0;302 free(dir);303 return r;304 }306 void307 synbad(char *s1, char *s2)308 {309 int len;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 }320 int321 isint(char *s, int *pans)322 {323 char *ep;325 *pans = strtol(s, &ep, 0);326 return (*ep == 0);327 }329 int330 isolder(char *pin, char *f)331 {332 int r;333 ulong n, m;334 char *p = pin;335 Dir *dir;337 dir = dirstat(f);338 if (dir == nil)339 return 0;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 }373 r = dir->mtime + n < time(0);374 free(dir);375 return r;376 }378 int379 isolderthan(char *a, char *b)380 {381 int r;382 Dir *ad, *bd;384 ad = dirstat(a);385 bd = dirstat(b);386 if (ad == nil || bd == nil)387 r = 0;388 else389 r = ad->mtime > bd->mtime;390 free(ad);391 free(bd);392 return r;393 }395 int396 isnewerthan(char *a, char *b)397 {398 int r;399 Dir *ad, *bd;401 ad = dirstat(a);402 bd = dirstat(b);403 if (ad == nil || bd == nil)404 r = 0;405 else406 r = ad->mtime < bd->mtime;407 free(ad);408 free(bd);409 return r;410 }