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