VirtualBox

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

Last change on this file since 1286 was 1233, checked in by bird, 17 years ago

keywords.

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