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