xref: /openbsd-src/bin/csh/exp.c (revision df930be708d50e9715f173caa26ffe1b7599b157)
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 = &paraml1;
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(&paraml1);
629     t = syntax(paraml1.next, &paraml1, 0);
630     if (seterr)
631 	stderror(ERR_OLD);
632     execute(t, -1, NULL, NULL);
633     freelex(&paraml1), 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