9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | LICENSE

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 }