Merge commit '00f1a4f432b3d8aad1aa270e91c44c57f03ef407'
[unleashed.git] / usr / src / cmd / csh / sh.exp.c
blob298446b74bd532f1acf126c320a80e5e0da4f7a1
1 /*
2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
9 /*
10 * Copyright (c) 1980 Regents of the University of California.
11 * All rights reserved. The Berkeley Software License Agreement
12 * specifies the terms and conditions for redistribution.
15 #pragma ident "%Z%%M% %I% %E% SMI"
17 #include "sh.h"
18 #include "sh.tconst.h"
21 * C shell
24 #define IGNORE 1 /* in ignore, it means to ignore value, just parse */
25 #define NOGLOB 2 /* in ignore, it means not to globone */
27 #define ADDOP 1
28 #define MULOP 2
29 #define EQOP 4
30 #define RELOP 8
31 #define RESTOP 16
32 #define ANYOP 31
34 #define EQEQ 1
35 #define GTR 2
36 #define LSS 4
37 #define NOTEQ 6
38 #define EQMATCH 7
39 #define NOTEQMATCH 8
41 int exp0(tchar ***, bool);
42 int exp1(tchar ***, bool);
43 int exp2(tchar ***, bool);
44 int exp2a(tchar ***, bool);
45 int exp2b(tchar ***, bool);
46 int exp2c(tchar ***, bool);
47 tchar *exp3(tchar ***, bool);
48 tchar *exp3a(tchar ***, bool);
49 tchar *exp4(tchar ***, bool);
50 tchar *exp5(tchar ***, bool);
51 tchar *exp6(tchar ***, bool);
52 void evalav(tchar **);
55 * Determine if file given by name is accessible with permissions
56 * given by mode.
58 * Borrowed from the Bourne sh, and modified a bit
60 * If the requested access is permitted, a value of 0 is
61 * returned. Otherwise, a value of -1 is returned and errno is
62 * set to indicate the error
65 int
66 chk_access(tchar *path, mode_t mode)
68 static int flag;
69 static uid_t euid;
70 struct stat statb;
71 mode_t ftype;
72 unsigned char name[MAXPATHLEN*MB_LEN_MAX]; /* General use buffer. */
74 /* convert tchar * to char * */
75 tstostr(name, path);
77 if (flag == 0) {
78 euid = geteuid();
79 flag = 1;
81 if (stat((char *)name, &statb) == 0) {
82 ftype = statb.st_mode & S_IFMT;
83 if (access((char *)name, 010|(mode>>6)) == 0) {
84 if (euid == 0) {
85 if (ftype != S_IFREG || mode != S_IEXEC)
86 return (0);
87 /* root can execute file as long as it has execute
88 permission for someone */
89 if (statb.st_mode & (S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6)))
90 return (0);
91 return (-1);
93 return (0);
96 return (-1);
99 int
100 exp(tchar ***vp)
102 #ifdef TRACE
103 tprintf("TRACE- exp()\n");
104 #endif
106 return (exp0(vp, 0));
110 exp0(tchar ***vp, bool ignore)
112 int p1 = exp1(vp, ignore);
113 #ifdef TRACE
114 tprintf("TRACE- exp0()\n");
115 #endif
117 #ifdef EDEBUG
118 etraci("exp0 p1", p1, vp);
119 #endif
120 if (**vp && eq(**vp, S_BARBAR /* "||" */)) {
121 int p2;
123 (*vp)++;
124 p2 = exp0(vp, (ignore&IGNORE) || p1);
125 #ifdef EDEBUG
126 etraci("exp0 p2", p2, vp);
127 #endif
128 return (p1 || p2);
130 return (p1);
134 exp1(tchar ***vp, bool ignore)
136 int p1 = exp2(vp, ignore);
138 #ifdef TRACE
139 tprintf("TRACE- exp1()\n");
140 #endif
141 #ifdef EDEBUG
142 etraci("exp1 p1", p1, vp);
143 #endif
144 if (**vp && eq(**vp, S_ANDAND /* "&&" */)) {
145 int p2;
147 (*vp)++;
148 p2 = exp1(vp, (ignore&IGNORE) || !p1);
149 #ifdef EDEBUG
150 etraci("exp1 p2", p2, vp);
151 #endif
152 return (p1 && p2);
154 return (p1);
158 exp2(tchar ***vp, bool ignore)
160 int p1 = exp2a(vp, ignore);
162 #ifdef TRACE
163 tprintf("TRACE- exp2()\n");
164 #endif
165 #ifdef EDEBUG
166 etraci("exp3 p1", p1, vp);
167 #endif
168 if (**vp && eq(**vp, S_BAR /* "|" */)) {
169 int p2;
171 (*vp)++;
172 p2 = exp2(vp, ignore);
173 #ifdef EDEBUG
174 etraci("exp3 p2", p2, vp);
175 #endif
176 return (p1 | p2);
178 return (p1);
182 exp2a(tchar ***vp, bool ignore)
184 int p1 = exp2b(vp, ignore);
186 #ifdef TRACE
187 tprintf("TRACE- exp2a()\n");
188 #endif
189 #ifdef EDEBUG
190 etraci("exp2a p1", p1, vp);
191 #endif
192 if (**vp && eq(**vp, S_HAT /* "^" */)) {
193 int p2;
195 (*vp)++;
196 p2 = exp2a(vp, ignore);
197 #ifdef EDEBUG
198 etraci("exp2a p2", p2, vp);
199 #endif
200 return (p1 ^ p2);
202 return (p1);
206 exp2b(tchar ***vp, bool ignore)
208 int p1 = exp2c(vp, ignore);
210 #ifdef TRACE
211 tprintf("TRACE- exp2b()\n");
212 #endif
213 #ifdef EDEBUG
214 etraci("exp2b p1", p1, vp);
215 #endif
216 if (**vp && eq(**vp, S_AND /* "&" */)) {
217 int p2;
219 (*vp)++;
220 p2 = exp2b(vp, ignore);
221 #ifdef EDEBUG
222 etraci("exp2b p2", p2, vp);
223 #endif
224 return (p1 & p2);
226 return (p1);
230 exp2c(tchar ***vp, bool ignore)
232 tchar *p1 = exp3(vp, ignore);
233 tchar *p2;
234 int i;
236 #ifdef TRACE
237 tprintf("TRACE- exp2c()\n");
238 #endif
239 #ifdef EDEBUG
240 etracc("exp2c p1", p1, vp);
241 #endif
242 if (i = isa(**vp, EQOP)) {
243 (*vp)++;
244 if (i == EQMATCH || i == NOTEQMATCH)
245 ignore |= NOGLOB;
246 p2 = exp3(vp, ignore);
247 #ifdef EDEBUG
248 etracc("exp2c p2", p2, vp);
249 #endif
250 if (!(ignore&IGNORE)) switch (i) {
252 case EQEQ:
253 i = eq(p1, p2);
254 break;
256 case NOTEQ:
257 i = !eq(p1, p2);
258 break;
260 case EQMATCH:
261 i = Gmatch(p1, p2);
262 break;
264 case NOTEQMATCH:
265 i = !Gmatch(p1, p2);
266 break;
268 xfree(p1), xfree(p2);
269 return (i);
271 i = egetn(p1);
272 xfree(p1);
273 return (i);
276 tchar *
277 exp3(tchar ***vp, bool ignore)
279 tchar *p1, *p2;
280 int i;
282 #ifdef TRACE
283 tprintf("TRACE- exp3()\n");
284 #endif
285 p1 = exp3a(vp, ignore);
286 #ifdef EDEBUG
287 etracc("exp3 p1", p1, vp);
288 #endif
289 if (i = isa(**vp, RELOP)) {
290 (*vp)++;
291 if (**vp && eq(**vp, S_EQ /* "=" */))
292 i |= 1, (*vp)++;
293 p2 = exp3(vp, ignore);
294 #ifdef EDEBUG
295 etracc("exp3 p2", p2, vp);
296 #endif
297 if (!(ignore&IGNORE)) switch (i) {
299 case GTR:
300 i = egetn(p1) > egetn(p2);
301 break;
303 case GTR|1:
304 i = egetn(p1) >= egetn(p2);
305 break;
307 case LSS:
308 i = egetn(p1) < egetn(p2);
309 break;
311 case LSS|1:
312 i = egetn(p1) <= egetn(p2);
313 break;
315 xfree(p1), xfree(p2);
316 return (putn(i));
318 return (p1);
321 tchar *
322 exp3a(tchar ***vp, bool ignore)
324 tchar *p1, *p2, *op;
325 int i;
327 #ifdef TRACE
328 tprintf("TRACE- exp3a()\n");
329 #endif
330 p1 = exp4(vp, ignore);
331 #ifdef EDEBUG
332 etracc("exp3a p1", p1, vp);
333 #endif
334 op = **vp;
335 /* if (op && any(op[0], "<>") && op[0] == op[1]) { */
336 if (op && (op[0] == '<' || op[0] == '>') && op[0] == op[1]) {
337 (*vp)++;
338 p2 = exp3a(vp, ignore);
339 #ifdef EDEBUG
340 etracc("exp3a p2", p2, vp);
341 #endif
342 if (op[0] == '<')
343 i = egetn(p1) << egetn(p2);
344 else
345 i = egetn(p1) >> egetn(p2);
346 xfree(p1), xfree(p2);
347 return (putn(i));
349 return (p1);
352 tchar *
353 exp4(tchar ***vp, bool ignore)
355 tchar *p1, *p2;
356 int i = 0;
358 #ifdef TRACE
359 tprintf("TRACE- exp4()\n");
360 #endif
361 p1 = exp5(vp, ignore);
362 #ifdef EDEBUG
363 etracc("exp4 p1", p1, vp);
364 #endif
365 if (isa(**vp, ADDOP)) {
366 tchar *op = *(*vp)++;
368 p2 = exp4(vp, ignore);
369 #ifdef EDEBUG
370 etracc("exp4 p2", p2, vp);
371 #endif
372 if (!(ignore&IGNORE)) switch (op[0]) {
374 case '+':
375 i = egetn(p1) + egetn(p2);
376 break;
378 case '-':
379 i = egetn(p1) - egetn(p2);
380 break;
382 xfree(p1), xfree(p2);
383 return (putn(i));
385 return (p1);
388 tchar *
389 exp5(tchar ***vp, bool ignore)
391 tchar *p1, *p2;
392 int i = 0;
394 #ifdef TRACE
395 tprintf("TRACE- exp5()\n");
396 #endif
397 p1 = exp6(vp, ignore);
398 #ifdef EDEBUG
399 etracc("exp5 p1", p1, vp);
400 #endif
401 if (isa(**vp, MULOP)) {
402 tchar *op = *(*vp)++;
404 p2 = exp5(vp, ignore);
405 #ifdef EDEBUG
406 etracc("exp5 p2", p2, vp);
407 #endif
408 if (!(ignore&IGNORE)) switch (op[0]) {
410 case '*':
411 i = egetn(p1) * egetn(p2);
412 break;
414 case '/':
415 i = egetn(p2);
416 if (i == 0)
417 error("Divide by 0");
418 i = egetn(p1) / i;
419 break;
421 case '%':
422 i = egetn(p2);
423 if (i == 0)
424 error("Mod by 0");
425 i = egetn(p1) % i;
426 break;
428 xfree(p1), xfree(p2);
429 return (putn(i));
431 return (p1);
434 tchar *
435 exp6(tchar ***vp, bool ignore)
437 int ccode, i;
438 tchar *cp, *dp, *ep;
440 #ifdef TRACE
441 tprintf("TRACE- exp6()\n");
442 #endif
443 if (**vp == 0)
444 bferr("Expression syntax");
445 if (eq(**vp, S_EXAS /* "!" */)) {
446 (*vp)++;
447 cp = exp6(vp, ignore);
448 #ifdef EDEBUG
449 etracc("exp6 ! cp", cp, vp);
450 #endif
451 i = egetn(cp);
452 xfree(cp);
453 return (putn(!i));
455 if (eq(**vp, S_TIL /* "~" */)) {
456 (*vp)++;
457 cp = exp6(vp, ignore);
458 #ifdef EDEBUG
459 etracc("exp6 ~ cp", cp, vp);
460 #endif
461 i = egetn(cp);
462 xfree(cp);
463 return (putn(~i));
465 if (eq(**vp, S_LPAR /* "(" */)) {
466 (*vp)++;
467 ccode = exp0(vp, ignore);
468 #ifdef EDEBUG
469 etraci("exp6 () ccode", ccode, vp);
470 #endif
471 if (*vp == 0 || **vp == 0 || ***vp != ')')
472 bferr("Expression syntax");
473 (*vp)++;
474 return (putn(ccode));
476 if (eq(**vp, S_LBRA /* "{" */)) {
477 tchar **v;
478 struct command faket;
479 tchar *fakecom[2];
481 faket.t_dtyp = TCOM;
482 faket.t_dflg = 0;
483 faket.t_dcar = faket.t_dcdr = faket.t_dspr = NULL;
484 faket.t_dcom = fakecom;
485 fakecom[0] = S_BRAPPPBRA /* "{ ... }" */;
486 fakecom[1] = NOSTR;
487 (*vp)++;
488 v = *vp;
489 for (;;) {
490 if (!**vp)
491 bferr("Missing }");
492 if (eq(*(*vp)++, S_RBRA /* "}" */))
493 break;
495 if (ignore&IGNORE)
496 return (S_ /* "" */);
497 psavejob();
498 if (pfork(&faket, -1) == 0) {
499 *--(*vp) = 0;
500 evalav(v);
501 exitstat();
503 pwait();
504 prestjob();
505 #ifdef EDEBUG
506 etraci("exp6 {} status", egetn(value("status")), vp);
507 #endif
508 return (putn(egetn(value(S_status /* "status" */)) == 0));
510 if (isa(**vp, ANYOP))
511 return (S_ /* "" */);
512 cp = *(*vp)++;
513 if (*cp == '-' && any(cp[1], S_erwxfdzo /* "erwxfdzo" */)) {
514 struct stat stb;
516 if (cp[2] != '\0')
517 bferr("Malformed file inquiry");
520 * Detect missing file names by checking for operator
521 * in the file name position. However, if an operator
522 * name appears there, we must make sure that there's
523 * no file by that name (e.g., "/") before announcing
524 * an error. Even this check isn't quite right, since
525 * it doesn't take globbing into account.
527 if ((**vp == NULL) || isa(**vp, ANYOP) && stat_(**vp, &stb))
528 bferr("Missing file name");
529 dp = *(*vp)++;
531 if (ignore&IGNORE)
532 return (S_ /* "" */);
533 ep = globone(dp);
534 switch (cp[1]) {
536 case 'r':
537 i = !chk_access(ep, S_IREAD);
538 break;
540 case 'w':
541 i = !chk_access(ep, S_IWRITE);
542 break;
544 case 'x':
545 i = !chk_access(ep, S_IEXEC);
546 break;
548 default:
549 if (stat_(ep, &stb)) {
550 xfree(ep);
551 return (S_0 /* "0" */);
553 switch (cp[1]) {
555 case 'f':
556 i = (stb.st_mode & S_IFMT) == S_IFREG;
557 break;
559 case 'd':
560 i = (stb.st_mode & S_IFMT) == S_IFDIR;
561 break;
563 case 'z':
564 i = stb.st_size == 0;
565 break;
567 case 'e':
568 i = 1;
569 break;
571 case 'o':
572 i = stb.st_uid == uid;
573 break;
576 #ifdef EDEBUG
577 etraci("exp6 -? i", i, vp);
578 #endif
579 xfree(ep);
580 return (putn(i));
582 #ifdef EDEBUG
583 etracc("exp6 default", cp, vp);
584 #endif
585 return (ignore&NOGLOB ? savestr(cp) : globone(cp));
588 void
589 evalav(tchar **v)
591 struct wordent paraml;
592 struct wordent *hp = &paraml;
593 struct command *t;
594 struct wordent *wdp = hp;
596 #ifdef TRACE
597 tprintf("TRACE- evalav()\n");
598 #endif
599 set(S_status /* "status" */, S_0 /* "0" */);
600 hp->prev = hp->next = hp;
601 hp->word = S_ /* "" */;
602 while (*v) {
603 struct wordent *new = (struct wordent *)xcalloc(1, sizeof *wdp);
605 new->prev = wdp;
606 new->next = hp;
607 wdp->next = new;
608 wdp = new;
609 wdp->word = savestr(*v++);
611 hp->prev = wdp;
612 alias(&paraml);
613 t = syntax(paraml.next, &paraml, 0);
614 if (err)
615 error("%s", gettext(err));
616 execute(t, -1);
617 freelex(&paraml), freesyn(t);
621 isa(tchar *cp, int what)
624 #ifdef TRACE
625 tprintf("TRACE- isa()\n");
626 #endif
627 if (cp == 0)
628 return ((what & RESTOP) != 0);
629 if (cp[1] == 0) {
630 if (what & ADDOP && (*cp == '+' || *cp == '-'))
631 return (1);
632 if (what & MULOP && (*cp == '*' || *cp == '/' || *cp == '%'))
633 return (1);
634 if (what & RESTOP && (*cp == '(' || *cp == ')' || *cp == '!' ||
635 *cp == '~' || *cp == '^' || *cp == '"'))
636 return (1);
637 } else if (cp[2] == 0) {
638 if (what & RESTOP) {
639 if (cp[0] == '|' && cp[1] == '&')
640 return (1);
641 if (cp[0] == '<' && cp[1] == '<')
642 return (1);
643 if (cp[0] == '>' && cp[1] == '>')
644 return (1);
646 if (what & EQOP) {
647 if (cp[0] == '=') {
648 if (cp[1] == '=')
649 return (EQEQ);
650 if (cp[1] == '~')
651 return (EQMATCH);
652 } else if (cp[0] == '!') {
653 if (cp[1] == '=')
654 return (NOTEQ);
655 if (cp[1] == '~')
656 return (NOTEQMATCH);
660 if (what & RELOP) {
661 if (*cp == '<')
662 return (LSS);
663 if (*cp == '>')
664 return (GTR);
666 return (0);
670 egetn(tchar *cp)
673 #ifdef TRACE
674 tprintf("TRACE- egetn()\n");
675 #endif
676 if (*cp && *cp != '-' && !digit(*cp))
677 bferr("Expression syntax");
678 return (getn(cp));
681 /* Phew! */
683 #ifdef EDEBUG
684 void
685 etraci(tchar *str, int i, tchar ***vp)
688 printf("%s=%d\t", str, i);
689 blkpr(*vp);
690 printf("\n");
693 void
694 etracc(tchar *str, tchar *cp, tchar ***vp)
697 printf("%s=%s\t", str, cp);
698 blkpr(*vp);
699 printf("\n");
701 #endif