xref: /original-bsd/local/toolchest/ksh/sh/test.c (revision 2260fd55)
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