VirtualBox

source: kBuild/trunk/src/kash/bltin/test.c@ 1208

Last change on this file since 1208 was 1206, checked in by bird, 17 years ago

some more.

  • Property svn:eol-style set to native
File size: 9.3 KB
Line 
1/* $NetBSD: test.c,v 1.26 2005/02/10 06:56:55 simonb Exp $ */
2
3/*
4 * test(1); version 7-like -- author Erik Baalbergen
5 * modified by Eric Gisin to be used as built-in.
6 * modified by Arnold Robbins to add SVR3 compatibility
7 * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
8 * modified by J.T. Conklin for NetBSD.
9 *
10 * This program is in the Public Domain.
11 */
12
13#ifdef HAVE_SYS_CDEFS_H
14#include <sys/cdefs.h>
15#endif
16#ifndef lint
17__RCSID("$NetBSD: test.c,v 1.26 2005/02/10 06:56:55 simonb Exp $");
18#endif
19
20#include <sys/types.h>
21
22#include <ctype.h>
23#include <errno.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <stdarg.h>
28
29#include "error.h"
30#include "shinstance.h"
31
32
33/* test(1) accepts the following grammar:
34 oexpr ::= aexpr | aexpr "-o" oexpr ;
35 aexpr ::= nexpr | nexpr "-a" aexpr ;
36 nexpr ::= primary | "!" primary
37 primary ::= unary-operator operand
38 | operand binary-operator operand
39 | operand
40 | "(" oexpr ")"
41 ;
42 unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
43 "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
44
45 binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
46 "-nt"|"-ot"|"-ef";
47 operand ::= <any legal UNIX file name>
48*/
49
50enum token {
51 EOI,
52 FILRD,
53 FILWR,
54 FILEX,
55 FILEXIST,
56 FILREG,
57 FILDIR,
58 FILCDEV,
59 FILBDEV,
60 FILFIFO,
61 FILSOCK,
62 FILSYM,
63 FILGZ,
64 FILTT,
65 FILSUID,
66 FILSGID,
67 FILSTCK,
68 FILNT,
69 FILOT,
70 FILEQ,
71 FILUID,
72 FILGID,
73 STREZ,
74 STRNZ,
75 STREQ,
76 STRNE,
77 STRLT,
78 STRGT,
79 INTEQ,
80 INTNE,
81 INTGE,
82 INTGT,
83 INTLE,
84 INTLT,
85 UNOT,
86 BAND,
87 BOR,
88 LPAREN,
89 RPAREN,
90 OPERAND
91};
92
93enum token_types {
94 UNOP,
95 BINOP,
96 BUNOP,
97 BBINOP,
98 PAREN
99};
100
101static struct t_op {
102 const char *op_text;
103 short op_num, op_type;
104} const ops [] = {
105 {"-r", FILRD, UNOP},
106 {"-w", FILWR, UNOP},
107 {"-x", FILEX, UNOP},
108 {"-e", FILEXIST,UNOP},
109 {"-f", FILREG, UNOP},
110 {"-d", FILDIR, UNOP},
111 {"-c", FILCDEV,UNOP},
112 {"-b", FILBDEV,UNOP},
113 {"-p", FILFIFO,UNOP},
114 {"-u", FILSUID,UNOP},
115 {"-g", FILSGID,UNOP},
116 {"-k", FILSTCK,UNOP},
117 {"-s", FILGZ, UNOP},
118 {"-t", FILTT, UNOP},
119 {"-z", STREZ, UNOP},
120 {"-n", STRNZ, UNOP},
121 {"-h", FILSYM, UNOP}, /* for backwards compat */
122 {"-O", FILUID, UNOP},
123 {"-G", FILGID, UNOP},
124 {"-L", FILSYM, UNOP},
125 {"-S", FILSOCK,UNOP},
126 {"=", STREQ, BINOP},
127 {"!=", STRNE, BINOP},
128 {"<", STRLT, BINOP},
129 {">", STRGT, BINOP},
130 {"-eq", INTEQ, BINOP},
131 {"-ne", INTNE, BINOP},
132 {"-ge", INTGE, BINOP},
133 {"-gt", INTGT, BINOP},
134 {"-le", INTLE, BINOP},
135 {"-lt", INTLT, BINOP},
136 {"-nt", FILNT, BINOP},
137 {"-ot", FILOT, BINOP},
138 {"-ef", FILEQ, BINOP},
139 {"!", UNOT, BUNOP},
140 {"-a", BAND, BBINOP},
141 {"-o", BOR, BBINOP},
142 {"(", LPAREN, PAREN},
143 {")", RPAREN, PAREN},
144 {0, 0, 0}
145};
146
147//static char **t_wp;
148//static struct t_op const *t_wp_op;
149
150static void syntax(shinstance *, const char *, const char *);
151static int oexpr(shinstance *, enum token);
152static int aexpr(shinstance *, enum token);
153static int nexpr(shinstance *, enum token);
154static int primary(shinstance *, enum token);
155static int binop(shinstance *);
156static int filstat(shinstance *, char *, enum token);
157static enum token t_lex(shinstance *, char *);
158static int isoperand(shinstance *);
159static int getn(shinstance *, const char *);
160static int newerf(shinstance *, const char *, const char *);
161static int olderf(shinstance *, const char *, const char *);
162static int equalf(shinstance *, const char *, const char *);
163
164
165int
166testcmd(shinstance *psh, int argc, char **argv)
167{
168 int res;
169
170 if (strcmp(argv[0], "[") == 0) {
171 if (strcmp(argv[--argc], "]"))
172 error(psh, "missing ]");
173 argv[argc] = NULL;
174 }
175
176 if (argc < 2)
177 return 1;
178
179 psh->t_wp_op = NULL;
180 psh->t_wp = &argv[1];
181 res = !oexpr(psh, t_lex(psh, *psh->t_wp));
182
183 if (*psh->t_wp != NULL && *++psh->t_wp != NULL)
184 syntax(psh, *psh->t_wp, "unexpected operator");
185
186 return res;
187}
188
189static void
190syntax(shinstance *psh, const char *op, const char *msg)
191{
192
193 if (op && *op)
194 error(psh, "%s: %s", op, msg);
195 else
196 error(psh, "%s", msg);
197}
198
199static int
200oexpr(shinstance *psh, enum token n)
201{
202 int res;
203
204 res = aexpr(psh, n);
205 if (t_lex(psh, *++psh->t_wp) == BOR)
206 return oexpr(psh, t_lex(psh, *++psh->t_wp)) || res;
207 psh->t_wp--;
208 return res;
209}
210
211static int
212aexpr(shinstance *psh, enum token n)
213{
214 int res;
215
216 res = nexpr(psh, n);
217 if (t_lex(psh, *++psh->t_wp) == BAND)
218 return aexpr(psh, t_lex(psh, *++psh->t_wp)) && res;
219 psh->t_wp--;
220 return res;
221}
222
223static int
224nexpr(shinstance *psh, enum token n)
225{
226
227 if (n == UNOT)
228 return !nexpr(psh, t_lex(psh, *++psh->t_wp));
229 return primary(psh, n);
230}
231
232static int
233primary(shinstance *psh, enum token n)
234{
235 enum token nn;
236 int res;
237
238 if (n == EOI)
239 return 0; /* missing expression */
240 if (n == LPAREN) {
241 if ((nn = t_lex(psh, *++psh->t_wp)) == RPAREN)
242 return 0; /* missing expression */
243 res = oexpr(psh, nn);
244 if (t_lex(psh, *++psh->t_wp) != RPAREN)
245 syntax(psh, NULL, "closing paren expected");
246 return res;
247 }
248 if (psh->t_wp_op && psh->t_wp_op->op_type == UNOP) {
249 /* unary expression */
250 if (*++psh->t_wp == NULL)
251 syntax(psh, psh->t_wp_op->op_text, "argument expected");
252 switch (n) {
253 case STREZ:
254 return strlen(*psh->t_wp) == 0;
255 case STRNZ:
256 return strlen(*psh->t_wp) != 0;
257 case FILTT:
258 return shfile_isatty(&psh->fdtab, getn(psh, *psh->t_wp));
259 default:
260 return filstat(psh, *psh->t_wp, n);
261 }
262 }
263
264 if (t_lex(psh, psh->t_wp[1]), psh->t_wp_op && psh->t_wp_op->op_type == BINOP) {
265 return binop(psh);
266 }
267
268 return strlen(*psh->t_wp) > 0;
269}
270
271static int
272binop(shinstance *psh)
273{
274 const char *opnd1, *opnd2;
275 struct t_op const *op;
276
277 opnd1 = *psh->t_wp;
278 (void) t_lex(psh, *++psh->t_wp);
279 op = psh->t_wp_op;
280
281 if ((opnd2 = *++psh->t_wp) == NULL)
282 syntax(psh, op->op_text, "argument expected");
283
284 switch (op->op_num) {
285 case STREQ:
286 return strcmp(opnd1, opnd2) == 0;
287 case STRNE:
288 return strcmp(opnd1, opnd2) != 0;
289 case STRLT:
290 return strcmp(opnd1, opnd2) < 0;
291 case STRGT:
292 return strcmp(opnd1, opnd2) > 0;
293 case INTEQ:
294 return getn(psh, opnd1) == getn(psh, opnd2);
295 case INTNE:
296 return getn(psh, opnd1) != getn(psh, opnd2);
297 case INTGE:
298 return getn(psh, opnd1) >= getn(psh, opnd2);
299 case INTGT:
300 return getn(psh, opnd1) > getn(psh, opnd2);
301 case INTLE:
302 return getn(psh, opnd1) <= getn(psh, opnd2);
303 case INTLT:
304 return getn(psh, opnd1) < getn(psh, opnd2);
305 case FILNT:
306 return newerf(psh, opnd1, opnd2);
307 case FILOT:
308 return olderf(psh, opnd1, opnd2);
309 case FILEQ:
310 return equalf(psh, opnd1, opnd2);
311 default:
312 abort();
313 /* NOTREACHED */
314 return -1;
315 }
316}
317
318static int
319filstat(shinstance *psh, char *nm, enum token mode)
320{
321 struct stat s;
322
323 if (mode == FILSYM
324 ? shfile_lstat(&psh->fdtab, nm, &s)
325 : shfile_stat(&psh->fdtab, nm, &s))
326 return 0;
327
328 switch (mode) {
329 case FILRD:
330 return shfile_access(&psh->fdtab, nm, R_OK) == 0;
331 case FILWR:
332 return shfile_access(&psh->fdtab, nm, W_OK) == 0;
333 case FILEX:
334 return shfile_access(&psh->fdtab, nm, X_OK) == 0;
335 case FILEXIST:
336 return shfile_access(&psh->fdtab, nm, F_OK) == 0;
337 case FILREG:
338 return S_ISREG(s.st_mode);
339 case FILDIR:
340 return S_ISDIR(s.st_mode);
341 case FILCDEV:
342#ifdef S_ISCHR
343 return S_ISCHR(s.st_mode);
344#else
345 return 0;
346#endif
347 case FILBDEV:
348#ifdef S_ISBLK
349 return S_ISBLK(s.st_mode);
350#else
351 return 0;
352#endif
353 case FILFIFO:
354#ifdef S_ISFIFO
355 return S_ISFIFO(s.st_mode);
356#else
357 return 0;
358#endif
359 case FILSOCK:
360#ifdef S_ISSOCK
361 return S_ISSOCK(s.st_mode);
362#else
363 return 0;
364#endif
365 case FILSYM:
366 return S_ISLNK(s.st_mode);
367 case FILSUID:
368 return (s.st_mode & S_ISUID) != 0;
369 case FILSGID:
370 return (s.st_mode & S_ISGID) != 0;
371 case FILSTCK:
372#ifdef S_ISVTX
373 return (s.st_mode & S_ISVTX) != 0;
374#else
375 return 0;
376#endif
377 case FILGZ:
378 return s.st_size > (off_t)0;
379 case FILUID:
380 return s.st_uid == sh_geteuid(psh);
381 case FILGID:
382 return s.st_gid == sh_getegid(psh);
383 default:
384 return 1;
385 }
386}
387
388static enum token
389t_lex(shinstance *psh, char *s)
390{
391 struct t_op const *op;
392
393 op = ops;
394
395 if (s == 0) {
396 psh->t_wp_op = NULL;
397 return EOI;
398 }
399 while (op->op_text) {
400 if (strcmp(s, op->op_text) == 0) {
401 if ((op->op_type == UNOP && isoperand(psh)) ||
402 (op->op_num == LPAREN && *(psh->t_wp+1) == 0))
403 break;
404 psh->t_wp_op = op;
405 return op->op_num;
406 }
407 op++;
408 }
409 psh->t_wp_op = NULL;
410 return OPERAND;
411}
412
413static int
414isoperand(shinstance *psh)
415{
416 struct t_op const *op;
417 char *s, *t;
418
419 op = ops;
420 if ((s = *(psh->t_wp+1)) == 0)
421 return 1;
422 if ((t = *(psh->t_wp+2)) == 0)
423 return 0;
424 while (op->op_text) {
425 if (strcmp(s, op->op_text) == 0)
426 return op->op_type == BINOP &&
427 (t[0] != ')' || t[1] != '\0');
428 op++;
429 }
430 return 0;
431}
432
433/* atoi with error detection */
434static int
435getn(shinstance *psh, const char *s)
436{
437 char *p;
438 long r;
439
440 errno = 0;
441 r = strtol(s, &p, 10);
442
443 if (errno != 0)
444 error(psh, "%s: out of range", s);
445
446 while (isspace((unsigned char)*p))
447 p++;
448
449 if (*p)
450 error(psh, "%s: bad number", s);
451
452 return (int) r;
453}
454
455static int
456newerf(shinstance *psh, const char *f1, const char *f2)
457{
458 struct stat b1, b2;
459
460 return (shfile_stat(&psh->fdtab, f1, &b1) == 0 &&
461 shfile_stat(&psh->fdtab, f2, &b2) == 0 &&
462 b1.st_mtime > b2.st_mtime);
463}
464
465static int
466olderf(shinstance *psh, const char *f1, const char *f2)
467{
468 struct stat b1, b2;
469
470 return (shfile_stat(&psh->fdtab, f1, &b1) == 0 &&
471 shfile_stat(&psh->fdtab, f2, &b2) == 0 &&
472 b1.st_mtime < b2.st_mtime);
473}
474
475static int
476equalf(shinstance *psh, const char *f1, const char *f2)
477{
478 struct stat b1, b2;
479
480 return (shfile_stat(&psh->fdtab, f1, &b1) == 0 &&
481 shfile_stat(&psh->fdtab, f2, &b2) == 0 &&
482 b1.st_dev == b2.st_dev &&
483 b1.st_ino == b2.st_ino);
484}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette