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