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
testfn(argn,com)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
exp(flag)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
nxtarg(mt)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
e3()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
ftype(f,mask,field)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
fsizep(f)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
ftime_compare(file1,file2)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
eq_inode(file1,file2)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