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