|
|
1.1 root 1: /*
2: * test(1); version 7-like -- author Erik Baalbergen
3: * modified by Eric Gisin to be used as built-in.
4: * modified by Arnold Robbins to add SVR3 compatibility
5: * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
6: */
7:
8: static char *RCSid = "$Header: c_test.c,v 3.1 88/11/03 09:14:43 egisin Exp $";
9:
10: #include <stddef.h>
11: #include <stdlib.h>
12: #include <string.h>
13: #include <signal.h>
14: #include <errno.h>
15: #include <setjmp.h>
16: #include <sys/types.h>
17: #include <sys/stat.h>
18: #include "sh.h"
19:
20: /* test(1) accepts the following grammar:
21: expr ::= bexpr | bexpr "-o" expr ;
22: bexpr ::= primary | primary "-a" bexpr ;
23: primary ::= unary-operator operand
24: | operand binary-operator operand
25: | operand
26: | "(" expr ")"
27: | "!" expr
28: ;
29: unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
30: "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
31:
32: binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
33: "-nt"|"-ot"|"-ef";
34: operand ::= <any legal UNIX file name>
35: */
36:
37: #define EOI 0
38: #define FILRD 1
39: #define FILWR 2
40: #define FILREG 3
41: #define FILID 4
42: #define FILGZ 5
43: #define FILTT 6
44: #define STZER 7
45: #define STNZE 8
46: #define STEQL 9
47: #define STNEQ 10
48: #define INTEQ 11
49: #define INTNE 12
50: #define INTGE 13
51: #define INTGT 14
52: #define INTLE 15
53: #define INTLT 16
54: #define UNEGN 17
55: #define BAND 18
56: #define BOR 19
57: #define LPAREN 20
58: #define RPAREN 21
59: #define OPERAND 22
60: #define FILEX 23
61: #define FILCDEV 24
62: #define FILBDEV 25
63: #define FILFIFO 26
64: #define FILSETU 27
65: #define FILSETG 28
66: #define FILSTCK 29
67: #define FILSYM 30
68: #define FILNT 31
69: #define FILOT 32
70: #define FILEQ 33
71: #define FILSOCK 34
72: #define FILUID 35
73: #define FILGID 36
74: #define OPTION 37
75:
76: #define UNOP 1
77: #define BINOP 2
78: #define BUNOP 3
79: #define BBINOP 4
80: #define PAREN 5
81:
82: struct t_op {
83: char *op_text;
84: short op_num, op_type;
85: } Const ops [] = {
86: {"-r", FILRD, UNOP},
87: {"-w", FILWR, UNOP},
88: {"-x", FILEX, UNOP},
89: {"-f", FILREG, UNOP},
90: {"-d", FILID, UNOP},
91: {"-c", FILCDEV,UNOP},
92: {"-b", FILBDEV,UNOP},
93: {"-p", FILFIFO,UNOP},
94: {"-u", FILSETU,UNOP},
95: {"-g", FILSETG,UNOP},
96: {"-k", FILSTCK,UNOP},
97: {"-s", FILGZ, UNOP},
98: {"-t", FILTT, UNOP},
99: {"-z", STZER, UNOP},
100: {"-n", STNZE, UNOP},
101: #if 0 /* conficts with binary -o */
102: {"-o", OPTION, UNOP},
103: #endif
104: {"-U", FILUID, UNOP},
105: {"-G", FILGID, UNOP},
106: {"-L", FILSYM, UNOP},
107: {"-S", FILSOCK,UNOP},
108: {"=", STEQL, BINOP},
109: {"!=", STNEQ, BINOP},
110: {"-eq", INTEQ, BINOP},
111: {"-ne", INTNE, BINOP},
112: {"-ge", INTGE, BINOP},
113: {"-gt", INTGT, BINOP},
114: {"-le", INTLE, BINOP},
115: {"-lt", INTLT, BINOP},
116: {"-nt", FILNT, BINOP},
117: {"-ot", FILOT, BINOP},
118: {"-ef", FILEQ, BINOP},
119: {"!", UNEGN, BUNOP},
120: {"-a", BAND, BBINOP},
121: {"-o", BOR, BBINOP},
122: {"(", LPAREN, PAREN},
123: {")", RPAREN, PAREN},
124: {0, 0, 0}
125: };
126:
127: char **t_wp;
128: struct t_op Const *t_wp_op;
129:
130: int
131: c_test(wp)
132: char **wp;
133: {
134: t_wp = wp+1;
135: if (strcmp(wp[0], "[") == 0) {
136: while (*wp != NULL)
137: wp++;
138: if (strcmp(*--wp, "]") != 0)
139: errorf("[: missing ]\n");
140: *wp = NULL;
141: }
142: #if 0
143: if (*t_wp == NULL)
144: mypr("*t_wp == NULL\n");
145: else if (!expr(t_lex(*t_wp)))
146: mypr("expr returned 0\n");
147: #endif
148: return *t_wp == NULL || !expr(t_lex(*t_wp));
149: }
150:
151: static
152: syntax()
153: {
154: errorf("test: syntax error\n");
155: }
156:
157: expr(n)
158: {
159: int res;
160:
161: if (n == EOI)
162: syntax();
163: res = bexpr(n);
164: if (t_lex(*++t_wp) == BOR)
165: return expr(t_lex(*++t_wp)) || res;
166: t_wp--;
167: return res;
168: }
169:
170: bexpr(n)
171: {
172: int res;
173:
174: if (n == EOI)
175: syntax();
176: res = primary(n);
177: if (t_lex(*++t_wp) == BAND)
178: return bexpr(t_lex(*++t_wp)) && res;
179: t_wp--;
180: return res;
181: }
182:
183: primary(n)
184: int n; /* token */
185: {
186: register char *opnd1, *opnd2;
187: int res;
188:
189: if (n == EOI)
190: syntax();
191: if (n == UNEGN)
192: return !expr(t_lex(*++t_wp));
193: if (n == LPAREN) {
194: res = expr(t_lex(*++t_wp));
195: if (t_lex(*++t_wp) != RPAREN)
196: syntax();
197: return res;
198: }
199: if (n == OPERAND) {
200: opnd1 = *t_wp;
201: (void) t_lex(*++t_wp);
202: if (t_wp_op && t_wp_op->op_type == BINOP) {
203: struct t_op Const *op = t_wp_op;
204:
205: if ((opnd2 = *++t_wp) == (char *)0)
206: syntax();
207:
208: switch (op->op_num) {
209: case STEQL:
210: return strcmp(opnd1, opnd2) == 0;
211: case STNEQ:
212: return strcmp(opnd1, opnd2) != 0;
213: case INTEQ:
214: return evaluate(opnd1) == evaluate(opnd2);
215: case INTNE:
216: return evaluate(opnd1) != evaluate(opnd2);
217: case INTGE:
218: return evaluate(opnd1) >= evaluate(opnd2);
219: case INTGT:
220: return evaluate(opnd1) > evaluate(opnd2);
221: case INTLE:
222: return evaluate(opnd1) <= evaluate(opnd2);
223: case INTLT:
224: return evaluate(opnd1) < evaluate(opnd2);
225: case FILNT:
226: return newerf (opnd1, opnd2);
227: case FILOT:
228: return olderf (opnd1, opnd2);
229: case FILEQ:
230: return equalf (opnd1, opnd2);
231: }
232: }
233: t_wp--;
234: return strlen(opnd1) > 0;
235: }
236: if (t_wp_op->op_type == UNOP) {
237: /* unary expression */
238: if (*++t_wp == NULL && n != FILTT)
239: syntax();
240: switch (n) {
241: case OPTION:
242: return flag[option(*t_wp)];
243: case STZER:
244: return strlen(*t_wp) == 0;
245: case STNZE:
246: return strlen(*t_wp) != 0;
247: case FILTT:
248: if (!digit(**t_wp))
249: return filstat("0", n);
250: default: /* all other FIL* */
251: return filstat(*t_wp, n);
252: }
253: }
254: syntax();
255: }
256:
257: filstat(nm, mode)
258: char *nm;
259: {
260: struct stat s;
261:
262: switch (mode) {
263: case FILRD:
264: return access(nm, 4) == 0;
265: case FILWR:
266: return access(nm, 2) == 0;
267: case FILEX:
268: return access(nm, 1) == 0;
269: case FILREG:
270: return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFREG;
271: case FILID:
272: return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFDIR;
273: case FILCDEV:
274: return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFCHR;
275: case FILBDEV:
276: return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFBLK;
277: case FILFIFO:
278: #ifdef S_IFIFO
279: return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFIFO;
280: #else
281: return 0;
282: #endif
283: case FILSETU:
284: return stat(nm, &s) == 0 && (s.st_mode & S_ISUID) == S_ISUID;
285: case FILSETG:
286: return stat(nm, &s) == 0 && (s.st_mode & S_ISGID) == S_ISGID;
287: case FILSTCK:
288: return stat(nm, &s) == 0 && (s.st_mode & S_ISVTX) == S_ISVTX;
289: case FILGZ:
290: return stat(nm, &s) == 0 && s.st_size > 0L;
291: case FILTT:
292: return isatty(getn(nm));
293: case FILUID:
294: return stat(nm, &s) == 0 && s.st_uid == geteuid();
295: case FILGID:
296: return stat(nm, &s) == 0 && s.st_gid == getegid();
297: #ifdef S_IFLNK
298: case FILSYM:
299: return lstat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFLNK;
300: #endif
301: #ifdef S_IFSOCK
302: case FILSOCK:
303: return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFSOCK;
304: #endif
305: default:
306: return 1;
307: }
308: }
309:
310: int
311: t_lex(s)
312: register char *s;
313: {
314: register struct t_op Const *op = ops;
315:
316: if (s == 0)
317: return EOI;
318: while (op->op_text) {
319: if (strcmp(s, op->op_text) == 0) {
320: t_wp_op = op;
321: return op->op_num;
322: }
323: op++;
324: }
325: t_wp_op = (struct t_op *)0;
326: return OPERAND;
327: }
328:
329: newerf (f1, f2)
330: char *f1, *f2;
331: {
332: struct stat b1, b2;
333:
334: return (stat (f1, &b1) == 0 &&
335: stat (f2, &b2) == 0 &&
336: b1.st_mtime > b2.st_mtime);
337: }
338:
339: olderf (f1, f2)
340: char *f1, *f2;
341: {
342: struct stat b1, b2;
343:
344: return (stat (f1, &b1) == 0 &&
345: stat (f2, &b2) == 0 &&
346: b1.st_mtime < b2.st_mtime);
347: }
348:
349: equalf (f1, f2)
350: char *f1, *f2;
351: {
352: struct stat b1, b2;
353:
354: return (stat (f1, &b1) == 0 &&
355: stat (f2, &b2) == 0 &&
356: b1.st_dev == b2.st_dev &&
357: b1.st_ino == b2.st_ino);
358: }
359:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.