1 /* 2 3 * Copyright (c) 1984, 1985, 1986 AT&T 4 * All Rights Reserved 5 6 * THIS IS UNPUBLISHED PROPRIETARY SOURCE 7 * CODE OF AT&T. 8 * The copyright notice above does not 9 * evidence any actual or intended 10 * publication of such source code. 11 12 */ 13 /* @(#)test.c 1.1 */ 14 /* 15 * test expression 16 * [ expression ] 17 * Rewritten by David Korn 18 */ 19 20 #include <sys/types.h> 21 #include <sys/stat.h> 22 #include "shtype.h" 23 #include "defs.h" 24 #include "test.h" 25 #include "sym.h" 26 27 #define tio(a,f) (access(a,f)==0) 28 /* single char string compare */ 29 #define c_eq(a,c) (*a==c && *(a+1)==0) 30 /* two character string compare */ 31 #define c2_eq(a,c1,c2) (*a==c1 && *(a+1)==c2 && *(a+2)==0) 32 33 int ftype(); 34 int testfn(); 35 36 extern long aeval(); 37 extern char *strchr(); 38 extern void failed(); 39 40 static char *nxtarg(); 41 static time_t ftime_compare(); 42 static int exp(); 43 static int e3(); 44 static int fsizep(); 45 46 extern MSG synmsg; 47 extern MSG test_opts; 48 49 static int ap, ac; 50 static char **av; 51 52 int testfn(argn, com) 53 char *com[]; 54 register int argn; 55 { 56 register char *p = com[0]; 57 av = com; 58 ap = 1; 59 if(c_eq(p,'[')) 60 { 61 p = com[--argn]; 62 if(!c_eq(p, ']')) 63 failed(btest, endmatch); 64 } 65 if(argn <= 1) 66 return(1); 67 ac = argn; 68 return(!exp(0)); 69 } 70 71 /* 72 * evaluate a test expression. 73 * flag is 0 on outer level 74 * flag is 1 when in parenthesis 75 * flag is 2 when evaluating -a 76 */ 77 78 static exp(flag) 79 { 80 register int r; 81 register char *p; 82 r = e3(); 83 while(ap < ac) 84 { 85 p = nxtarg(0); 86 /* check for -o and -a */ 87 if(flag && c_eq(p,')')) 88 { 89 ap--; 90 break; 91 } 92 if(*p=='-' && *(p+2)==0) 93 { 94 if(*++p == 'o') 95 { 96 if(flag==2) 97 { 98 ap--; 99 break; 100 } 101 r |= exp(3); 102 continue; 103 } 104 else if(*p == 'a') 105 { 106 r &= exp(2); 107 continue; 108 } 109 } 110 failed(btest, synmsg); 111 } 112 return(r); 113 } 114 115 static char *nxtarg(mt) 116 { 117 if(ap >= ac) 118 { 119 if(mt) 120 { 121 ap++; 122 return(0); 123 } 124 failed(btest, argexp); 125 } 126 return(av[ap++]); 127 } 128 129 130 static e3() 131 { 132 register char *a; 133 register char *p2; 134 register int p1; 135 long int int1, int2; 136 char *op; 137 a=nxtarg(0); 138 if(c_eq(a, '!')) 139 return(!e3()); 140 if(c_eq(a, '(')) 141 { 142 p1 = exp(1); 143 p2 = nxtarg(0); 144 if(!c_eq(p2, ')')) 145 failed(btest,parexp); 146 return(p1); 147 } 148 p2 = nxtarg(1); 149 if(p2!=0 && (c_eq(p2,'=') || c2_eq(p2,'!','='))) 150 goto skip; 151 if(c2_eq(a,'-','t')) 152 { 153 if(p2 && isdigit(*p2)) 154 return(*(p2+1)?0:isatty(*p2-'0')); 155 else 156 { 157 /* test -t with no arguments */ 158 ap--; 159 return(isatty(1)); 160 } 161 } 162 if((*a=='-' && *(a+2)==0) && strchr(test_opts,*(a+1))) 163 { 164 if(p2==0 || c_eq(p2,')') ) 165 failed(btest, argexp); 166 switch(*(a+1)) 167 { 168 case 'r': 169 return(tio(p2, 4)); 170 case 'w': 171 return(tio(p2, 2)); 172 case 'x': 173 return(tio(p2, 1)); 174 case 'd': 175 return(ftype(p2,S_IFMT,S_IFDIR)); 176 case 'c': 177 return(ftype(p2,S_IFMT,S_IFCHR)); 178 case 'b': 179 return(ftype(p2,S_IFMT,S_IFBLK)); 180 case 'f': 181 return(ftype(p2,S_IFMT,S_IFREG)); 182 case 'u': 183 return(ftype(p2,S_ISUID,S_ISUID)); 184 case 'g': 185 return(ftype(p2,S_ISGID,S_ISGID)); 186 case 'k': 187 return(ftype(p2,S_ISVTX,S_ISVTX)); 188 case 'L': 189 #ifdef S_IFLNK 190 { 191 struct stat statb; 192 if(lstat(p2,&statb)<0) 193 return(0); 194 return((statb.st_mode&S_IFMT)==S_IFLNK); 195 } 196 #else 197 return(0); 198 #endif /* S_IFLNK */ 199 case 'p': 200 #ifdef S_IFIFO 201 return(ftype(p2,S_IFIFO,S_IFIFO)); 202 #else 203 return(0); 204 #endif /* S_IFIFO */ 205 case 's': 206 return(fsizep(p2)); 207 case 'n': 208 return(*p2 != 0); 209 case 'z': 210 return(*p2 == 0); 211 } 212 } 213 if(p2==0 || c_eq(p2,')')) 214 { 215 ap--; 216 return(*a!=0); 217 } 218 skip: 219 p1 = syslook(p2,testops); 220 op = p2; 221 if((p1&TEST_BINOP)==0) 222 p2 = nxtarg(0); 223 if(p1==0) 224 failed(op,badop); 225 if(p1&TEST_ARITH) 226 { 227 int1 = aeval(a); 228 int2 = aeval(p2); 229 } 230 switch(p1) 231 { 232 /* p1 must be one of the following values */ 233 case TEST_AND: 234 case TEST_OR: 235 ap--; 236 return(*a!=0); 237 case TEST_SEQ: 238 return(eq(p2, a)); 239 case TEST_SNE: 240 return(!eq(p2, a)); 241 case TEST_EF: 242 return(eq_inode(p2,a)); 243 case TEST_NT: 244 return(ftime_compare(a,p2)>0); 245 case TEST_OT: 246 return(ftime_compare(a,p2)<0); 247 case TEST_EQ: 248 return(int1==int2); 249 case TEST_NE: 250 return(int1!=int2); 251 case TEST_GT: 252 return(int1>int2); 253 case TEST_LT: 254 return(int1<int2); 255 case TEST_GE: 256 return(int1>=int2); 257 case TEST_LE: 258 return(int1<=int2); 259 } 260 /* NOTREACHED */ 261 } 262 263 ftype(f,mask,field) 264 char *f; 265 int field; 266 { 267 struct stat statb; 268 if(stat(f,&statb)<0) 269 return(0); 270 return((statb.st_mode&mask)==field); 271 } 272 273 static fsizep(f) 274 char *f; 275 { 276 struct stat statb; 277 if(stat(f, &statb) <0) 278 return(0); 279 return(statb.st_size>0); 280 } 281 282 /* 283 * returns the modification time of f1 - modification time of f2 284 */ 285 286 static time_t ftime_compare(file1,file2) 287 char *file1,*file2; 288 { 289 struct stat statb1,statb2; 290 if(stat(file1,&statb1)<0) 291 statb1.st_mtime = 0; 292 if(stat(file2,&statb2)<0) 293 statb2.st_mtime = 0; 294 return(statb1.st_mtime-statb2.st_mtime); 295 } 296 297 /* 298 * return true if inode of two files are the same 299 */ 300 301 eq_inode(file1,file2) 302 char *file1,*file2; 303 { 304 struct stat stat1,stat2; 305 if(stat(file1,&stat1)>=0 && stat(file2,&stat2)>=0) 306 if(stat1.st_dev == stat2.st_dev && stat1.st_ino == stat2.st_ino) 307 return(1); 308 return(0); 309 } 310 311