1 /*-
2 * Copyright (c) 1980, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char sccsid[] = "@(#)exp.c 8.1 (Berkeley) 05/31/93";
10 #endif /* not lint */
11
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #ifndef SHORT_STRINGS
17 #include <string.h>
18 #endif /* SHORT_STRINGS */
19 #if __STDC__
20 # include <stdarg.h>
21 #else
22 # include <varargs.h>
23 #endif
24
25 #include "csh.h"
26 #include "extern.h"
27
28 #define IGNORE 1 /* in ignore, it means to ignore value, just parse */
29 #define NOGLOB 2 /* in ignore, it means not to globone */
30
31 #define ADDOP 1
32 #define MULOP 2
33 #define EQOP 4
34 #define RELOP 8
35 #define RESTOP 16
36 #define ANYOP 31
37
38 #define EQEQ 1
39 #define GTR 2
40 #define LSS 4
41 #define NOTEQ 6
42 #define EQMATCH 7
43 #define NOTEQMATCH 8
44
45 static int exp1 __P((Char ***, bool));
46 static int exp2 __P((Char ***, bool));
47 static int exp2a __P((Char ***, bool));
48 static int exp2b __P((Char ***, bool));
49 static int exp2c __P((Char ***, bool));
50 static Char * exp3 __P((Char ***, bool));
51 static Char * exp3a __P((Char ***, bool));
52 static Char * exp4 __P((Char ***, bool));
53 static Char * exp5 __P((Char ***, bool));
54 static Char * exp6 __P((Char ***, bool));
55 static void evalav __P((Char **));
56 static int isa __P((Char *, int));
57 static int egetn __P((Char *));
58
59 #ifdef EDEBUG
60 static void etracc __P((char *, Char *, Char ***));
61 static void etraci __P((char *, int, Char ***));
62 #endif
63
64 int
expr(vp)65 expr(vp)
66 register Char ***vp;
67 {
68 return (exp0(vp, 0));
69 }
70
71 int
exp0(vp,ignore)72 exp0(vp, ignore)
73 register Char ***vp;
74 bool ignore;
75 {
76 register int p1 = exp1(vp, ignore);
77
78 #ifdef EDEBUG
79 etraci("exp0 p1", p1, vp);
80 #endif
81 if (**vp && eq(**vp, STRor2)) {
82 register int p2;
83
84 (*vp)++;
85 p2 = exp0(vp, (ignore & IGNORE) || p1);
86 #ifdef EDEBUG
87 etraci("exp0 p2", p2, vp);
88 #endif
89 return (p1 || p2);
90 }
91 return (p1);
92 }
93
94 static int
exp1(vp,ignore)95 exp1(vp, ignore)
96 register Char ***vp;
97 bool ignore;
98 {
99 register int p1 = exp2(vp, ignore);
100
101 #ifdef EDEBUG
102 etraci("exp1 p1", p1, vp);
103 #endif
104 if (**vp && eq(**vp, STRand2)) {
105 register int p2;
106
107 (*vp)++;
108 p2 = exp1(vp, (ignore & IGNORE) || !p1);
109 #ifdef EDEBUG
110 etraci("exp1 p2", p2, vp);
111 #endif
112 return (p1 && p2);
113 }
114 return (p1);
115 }
116
117 static int
exp2(vp,ignore)118 exp2(vp, ignore)
119 register Char ***vp;
120 bool ignore;
121 {
122 register int p1 = exp2a(vp, ignore);
123
124 #ifdef EDEBUG
125 etraci("exp3 p1", p1, vp);
126 #endif
127 if (**vp && eq(**vp, STRor)) {
128 register int p2;
129
130 (*vp)++;
131 p2 = exp2(vp, ignore);
132 #ifdef EDEBUG
133 etraci("exp3 p2", p2, vp);
134 #endif
135 return (p1 | p2);
136 }
137 return (p1);
138 }
139
140 static int
exp2a(vp,ignore)141 exp2a(vp, ignore)
142 register Char ***vp;
143 bool ignore;
144 {
145 register int p1 = exp2b(vp, ignore);
146
147 #ifdef EDEBUG
148 etraci("exp2a p1", p1, vp);
149 #endif
150 if (**vp && eq(**vp, STRcaret)) {
151 register int p2;
152
153 (*vp)++;
154 p2 = exp2a(vp, ignore);
155 #ifdef EDEBUG
156 etraci("exp2a p2", p2, vp);
157 #endif
158 return (p1 ^ p2);
159 }
160 return (p1);
161 }
162
163 static int
exp2b(vp,ignore)164 exp2b(vp, ignore)
165 register Char ***vp;
166 bool ignore;
167 {
168 register int p1 = exp2c(vp, ignore);
169
170 #ifdef EDEBUG
171 etraci("exp2b p1", p1, vp);
172 #endif
173 if (**vp && eq(**vp, STRand)) {
174 register int p2;
175
176 (*vp)++;
177 p2 = exp2b(vp, ignore);
178 #ifdef EDEBUG
179 etraci("exp2b p2", p2, vp);
180 #endif
181 return (p1 & p2);
182 }
183 return (p1);
184 }
185
186 static int
exp2c(vp,ignore)187 exp2c(vp, ignore)
188 register Char ***vp;
189 bool ignore;
190 {
191 register Char *p1 = exp3(vp, ignore);
192 register Char *p2;
193 register int i;
194
195 #ifdef EDEBUG
196 etracc("exp2c p1", p1, vp);
197 #endif
198 if ((i = isa(**vp, EQOP)) != 0) {
199 (*vp)++;
200 if (i == EQMATCH || i == NOTEQMATCH)
201 ignore |= NOGLOB;
202 p2 = exp3(vp, ignore);
203 #ifdef EDEBUG
204 etracc("exp2c p2", p2, vp);
205 #endif
206 if (!(ignore & IGNORE))
207 switch (i) {
208
209 case EQEQ:
210 i = eq(p1, p2);
211 break;
212
213 case NOTEQ:
214 i = !eq(p1, p2);
215 break;
216
217 case EQMATCH:
218 i = Gmatch(p1, p2);
219 break;
220
221 case NOTEQMATCH:
222 i = !Gmatch(p1, p2);
223 break;
224 }
225 xfree((ptr_t) p1);
226 xfree((ptr_t) p2);
227 return (i);
228 }
229 i = egetn(p1);
230 xfree((ptr_t) p1);
231 return (i);
232 }
233
234 static Char *
exp3(vp,ignore)235 exp3(vp, ignore)
236 register Char ***vp;
237 bool ignore;
238 {
239 register Char *p1, *p2;
240 register int i;
241
242 p1 = exp3a(vp, ignore);
243 #ifdef EDEBUG
244 etracc("exp3 p1", p1, vp);
245 #endif
246 if ((i = isa(**vp, RELOP)) != 0) {
247 (*vp)++;
248 if (**vp && eq(**vp, STRequal))
249 i |= 1, (*vp)++;
250 p2 = exp3(vp, ignore);
251 #ifdef EDEBUG
252 etracc("exp3 p2", p2, vp);
253 #endif
254 if (!(ignore & IGNORE))
255 switch (i) {
256
257 case GTR:
258 i = egetn(p1) > egetn(p2);
259 break;
260
261 case GTR | 1:
262 i = egetn(p1) >= egetn(p2);
263 break;
264
265 case LSS:
266 i = egetn(p1) < egetn(p2);
267 break;
268
269 case LSS | 1:
270 i = egetn(p1) <= egetn(p2);
271 break;
272 }
273 xfree((ptr_t) p1);
274 xfree((ptr_t) p2);
275 return (putn(i));
276 }
277 return (p1);
278 }
279
280 static Char *
exp3a(vp,ignore)281 exp3a(vp, ignore)
282 register Char ***vp;
283 bool ignore;
284 {
285 register Char *p1, *p2, *op;
286 register int i;
287
288 p1 = exp4(vp, ignore);
289 #ifdef EDEBUG
290 etracc("exp3a p1", p1, vp);
291 #endif
292 op = **vp;
293 if (op && any("<>", op[0]) && op[0] == op[1]) {
294 (*vp)++;
295 p2 = exp3a(vp, ignore);
296 #ifdef EDEBUG
297 etracc("exp3a p2", p2, vp);
298 #endif
299 if (op[0] == '<')
300 i = egetn(p1) << egetn(p2);
301 else
302 i = egetn(p1) >> egetn(p2);
303 xfree((ptr_t) p1);
304 xfree((ptr_t) p2);
305 return (putn(i));
306 }
307 return (p1);
308 }
309
310 static Char *
exp4(vp,ignore)311 exp4(vp, ignore)
312 register Char ***vp;
313 bool ignore;
314 {
315 register Char *p1, *p2;
316 register int i = 0;
317
318 p1 = exp5(vp, ignore);
319 #ifdef EDEBUG
320 etracc("exp4 p1", p1, vp);
321 #endif
322 if (isa(**vp, ADDOP)) {
323 register Char *op = *(*vp)++;
324
325 p2 = exp4(vp, ignore);
326 #ifdef EDEBUG
327 etracc("exp4 p2", p2, vp);
328 #endif
329 if (!(ignore & IGNORE))
330 switch (op[0]) {
331
332 case '+':
333 i = egetn(p1) + egetn(p2);
334 break;
335
336 case '-':
337 i = egetn(p1) - egetn(p2);
338 break;
339 }
340 xfree((ptr_t) p1);
341 xfree((ptr_t) p2);
342 return (putn(i));
343 }
344 return (p1);
345 }
346
347 static Char *
exp5(vp,ignore)348 exp5(vp, ignore)
349 register Char ***vp;
350 bool ignore;
351 {
352 register Char *p1, *p2;
353 register int i = 0;
354
355 p1 = exp6(vp, ignore);
356 #ifdef EDEBUG
357 etracc("exp5 p1", p1, vp);
358 #endif
359 if (isa(**vp, MULOP)) {
360 register Char *op = *(*vp)++;
361
362 p2 = exp5(vp, ignore);
363 #ifdef EDEBUG
364 etracc("exp5 p2", p2, vp);
365 #endif
366 if (!(ignore & IGNORE))
367 switch (op[0]) {
368
369 case '*':
370 i = egetn(p1) * egetn(p2);
371 break;
372
373 case '/':
374 i = egetn(p2);
375 if (i == 0)
376 stderror(ERR_DIV0);
377 i = egetn(p1) / i;
378 break;
379
380 case '%':
381 i = egetn(p2);
382 if (i == 0)
383 stderror(ERR_MOD0);
384 i = egetn(p1) % i;
385 break;
386 }
387 xfree((ptr_t) p1);
388 xfree((ptr_t) p2);
389 return (putn(i));
390 }
391 return (p1);
392 }
393
394 static Char *
exp6(vp,ignore)395 exp6(vp, ignore)
396 register Char ***vp;
397 bool ignore;
398 {
399 int ccode, i = 0;
400 register Char *cp, *dp, *ep;
401
402 if (**vp == 0)
403 stderror(ERR_NAME | ERR_EXPRESSION);
404 if (eq(**vp, STRbang)) {
405 (*vp)++;
406 cp = exp6(vp, ignore);
407 #ifdef EDEBUG
408 etracc("exp6 ! cp", cp, vp);
409 #endif
410 i = egetn(cp);
411 xfree((ptr_t) cp);
412 return (putn(!i));
413 }
414 if (eq(**vp, STRtilde)) {
415 (*vp)++;
416 cp = exp6(vp, ignore);
417 #ifdef EDEBUG
418 etracc("exp6 ~ cp", cp, vp);
419 #endif
420 i = egetn(cp);
421 xfree((ptr_t) cp);
422 return (putn(~i));
423 }
424 if (eq(**vp, STRLparen)) {
425 (*vp)++;
426 ccode = exp0(vp, ignore);
427 #ifdef EDEBUG
428 etraci("exp6 () ccode", ccode, vp);
429 #endif
430 if (*vp == 0 || **vp == 0 || ***vp != ')')
431 stderror(ERR_NAME | ERR_EXPRESSION);
432 (*vp)++;
433 return (putn(ccode));
434 }
435 if (eq(**vp, STRLbrace)) {
436 register Char **v;
437 struct command faket;
438 Char *fakecom[2];
439
440 faket.t_dtyp = NODE_COMMAND;
441 faket.t_dflg = 0;
442 faket.t_dcar = faket.t_dcdr = faket.t_dspr = NULL;
443 faket.t_dcom = fakecom;
444 fakecom[0] = STRfakecom;
445 fakecom[1] = NULL;
446 (*vp)++;
447 v = *vp;
448 for (;;) {
449 if (!**vp)
450 stderror(ERR_NAME | ERR_MISSING, '}');
451 if (eq(*(*vp)++, STRRbrace))
452 break;
453 }
454 if (ignore & IGNORE)
455 return (Strsave(STRNULL));
456 psavejob();
457 if (pfork(&faket, -1) == 0) {
458 *--(*vp) = 0;
459 evalav(v);
460 exitstat();
461 }
462 pwait();
463 prestjob();
464 #ifdef EDEBUG
465 etraci("exp6 {} status", egetn(value(STRstatus)), vp);
466 #endif
467 return (putn(egetn(value(STRstatus)) == 0));
468 }
469 if (isa(**vp, ANYOP))
470 return (Strsave(STRNULL));
471 cp = *(*vp)++;
472 if (*cp == '-' && any("erwxfdzopls", cp[1])) {
473 struct stat stb;
474
475 if (cp[2] != '\0')
476 stderror(ERR_NAME | ERR_FILEINQ);
477 /*
478 * Detect missing file names by checking for operator in the file name
479 * position. However, if an operator name appears there, we must make
480 * sure that there's no file by that name (e.g., "/") before announcing
481 * an error. Even this check isn't quite right, since it doesn't take
482 * globbing into account.
483 */
484 if (isa(**vp, ANYOP) && stat(short2str(**vp), &stb))
485 stderror(ERR_NAME | ERR_FILENAME);
486
487 dp = *(*vp)++;
488 if (ignore & IGNORE)
489 return (Strsave(STRNULL));
490 ep = globone(dp, G_ERROR);
491 switch (cp[1]) {
492
493 case 'r':
494 i = !access(short2str(ep), R_OK);
495 break;
496
497 case 'w':
498 i = !access(short2str(ep), W_OK);
499 break;
500
501 case 'x':
502 i = !access(short2str(ep), X_OK);
503 break;
504
505 default:
506 if (
507 #ifdef S_IFLNK
508 cp[1] == 'l' ? lstat(short2str(ep), &stb) :
509 #endif
510 stat(short2str(ep), &stb)) {
511 xfree((ptr_t) ep);
512 return (Strsave(STR0));
513 }
514 switch (cp[1]) {
515
516 case 'f':
517 i = S_ISREG(stb.st_mode);
518 break;
519
520 case 'd':
521 i = S_ISDIR(stb.st_mode);
522 break;
523
524 case 'p':
525 #ifdef S_ISFIFO
526 i = S_ISFIFO(stb.st_mode);
527 #else
528 i = 0;
529 #endif
530 break;
531
532 case 'l':
533 #ifdef S_ISLNK
534 i = S_ISLNK(stb.st_mode);
535 #else
536 i = 0;
537 #endif
538 break;
539
540 case 's':
541 #ifdef S_ISSOCK
542 i = S_ISSOCK(stb.st_mode);
543 #else
544 i = 0;
545 #endif
546 break;
547
548 case 'z':
549 i = stb.st_size == 0;
550 break;
551
552 case 'e':
553 i = 1;
554 break;
555
556 case 'o':
557 i = stb.st_uid == uid;
558 break;
559 }
560 }
561 #ifdef EDEBUG
562 etraci("exp6 -? i", i, vp);
563 #endif
564 xfree((ptr_t) ep);
565 return (putn(i));
566 }
567 #ifdef EDEBUG
568 etracc("exp6 default", cp, vp);
569 #endif
570 return (ignore & NOGLOB ? Strsave(cp) : globone(cp, G_ERROR));
571 }
572
573 static void
evalav(v)574 evalav(v)
575 register Char **v;
576 {
577 struct wordent paraml1;
578 register struct wordent *hp = ¶ml1;
579 struct command *t;
580 register struct wordent *wdp = hp;
581
582 set(STRstatus, Strsave(STR0));
583 hp->prev = hp->next = hp;
584 hp->word = STRNULL;
585 while (*v) {
586 register struct wordent *new =
587 (struct wordent *) xcalloc(1, sizeof *wdp);
588
589 new->prev = wdp;
590 new->next = hp;
591 wdp->next = new;
592 wdp = new;
593 wdp->word = Strsave(*v++);
594 }
595 hp->prev = wdp;
596 alias(¶ml1);
597 t = syntax(paraml1.next, ¶ml1, 0);
598 if (seterr)
599 stderror(ERR_OLD);
600 execute(t, -1, NULL, NULL);
601 freelex(¶ml1), freesyn(t);
602 }
603
604 static int
isa(cp,what)605 isa(cp, what)
606 register Char *cp;
607 register int what;
608 {
609 if (cp == 0)
610 return ((what & RESTOP) != 0);
611 if (cp[1] == 0) {
612 if (what & ADDOP && (*cp == '+' || *cp == '-'))
613 return (1);
614 if (what & MULOP && (*cp == '*' || *cp == '/' || *cp == '%'))
615 return (1);
616 if (what & RESTOP && (*cp == '(' || *cp == ')' || *cp == '!' ||
617 *cp == '~' || *cp == '^' || *cp == '"'))
618 return (1);
619 }
620 else if (cp[2] == 0) {
621 if (what & RESTOP) {
622 if (cp[0] == '|' && cp[1] == '&')
623 return (1);
624 if (cp[0] == '<' && cp[1] == '<')
625 return (1);
626 if (cp[0] == '>' && cp[1] == '>')
627 return (1);
628 }
629 if (what & EQOP) {
630 if (cp[0] == '=') {
631 if (cp[1] == '=')
632 return (EQEQ);
633 if (cp[1] == '~')
634 return (EQMATCH);
635 }
636 else if (cp[0] == '!') {
637 if (cp[1] == '=')
638 return (NOTEQ);
639 if (cp[1] == '~')
640 return (NOTEQMATCH);
641 }
642 }
643 }
644 if (what & RELOP) {
645 if (*cp == '<')
646 return (LSS);
647 if (*cp == '>')
648 return (GTR);
649 }
650 return (0);
651 }
652
653 static int
egetn(cp)654 egetn(cp)
655 register Char *cp;
656 {
657 if (*cp && *cp != '-' && !Isdigit(*cp))
658 stderror(ERR_NAME | ERR_EXPRESSION);
659 return (getn(cp));
660 }
661
662 /* Phew! */
663
664 #ifdef EDEBUG
665 static void
etraci(str,i,vp)666 etraci(str, i, vp)
667 char *str;
668 int i;
669 Char ***vp;
670 {
671 (void) fprintf(csherr, "%s=%d\t", str, i);
672 blkpr(csherr, *vp);
673 (void) fprintf(csherr, "\n");
674 }
675 static void
etracc(str,cp,vp)676 etracc(str, cp, vp)
677 char *str;
678 Char *cp;
679 Char ***vp;
680 {
681 (void) fprintf(csherr, "%s=%s\t", str, vis_str(cp));
682 blkpr(csherr, *vp);
683 (void) fprintf(csherr, "\n");
684 }
685 #endif
686