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