17c478bdstevel@tonic-gate/*
2fd5e982blu * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
37c478bdstevel@tonic-gate * Use is subject to license terms.
47c478bdstevel@tonic-gate */
57c478bdstevel@tonic-gate
67c478bdstevel@tonic-gate/*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
77c478bdstevel@tonic-gate/*	  All Rights Reserved  	*/
87c478bdstevel@tonic-gate
97c478bdstevel@tonic-gate/*
107c478bdstevel@tonic-gate * Copyright (c) 1980 Regents of the University of California.
117c478bdstevel@tonic-gate * All rights reserved.  The Berkeley Software License Agreement
127c478bdstevel@tonic-gate * specifies the terms and conditions for redistribution.
137c478bdstevel@tonic-gate */
147c478bdstevel@tonic-gate
157c478bdstevel@tonic-gate#pragma ident	"%Z%%M%	%I%	%E% SMI"
167c478bdstevel@tonic-gate
177c478bdstevel@tonic-gate#include "sh.h"
187c478bdstevel@tonic-gate#include "sh.tconst.h"
197c478bdstevel@tonic-gate
207c478bdstevel@tonic-gate/*
217c478bdstevel@tonic-gate * C shell
227c478bdstevel@tonic-gate */
237c478bdstevel@tonic-gate
2465b0c20nakanon#define	IGNORE	1	/* in ignore, it means to ignore value, just parse */
2565b0c20nakanon#define	NOGLOB	2	/* in ignore, it means not to globone */
267c478bdstevel@tonic-gate
277c478bdstevel@tonic-gate#define	ADDOP	1
287c478bdstevel@tonic-gate#define	MULOP	2
297c478bdstevel@tonic-gate#define	EQOP	4
307c478bdstevel@tonic-gate#define	RELOP	8
317c478bdstevel@tonic-gate#define	RESTOP	16
327c478bdstevel@tonic-gate#define	ANYOP	31
337c478bdstevel@tonic-gate
347c478bdstevel@tonic-gate#define	EQEQ	1
357c478bdstevel@tonic-gate#define	GTR	2
367c478bdstevel@tonic-gate#define	LSS	4
377c478bdstevel@tonic-gate#define	NOTEQ	6
3865b0c20nakanon#define	EQMATCH 7
3965b0c20nakanon#define	NOTEQMATCH 8
407c478bdstevel@tonic-gate
416c02b4amuffinint	exp0(tchar ***, bool);
426c02b4amuffinint	exp1(tchar ***, bool);
436c02b4amuffinint	exp2(tchar ***, bool);
446c02b4amuffinint	exp2a(tchar ***, bool);
456c02b4amuffinint	exp2b(tchar ***, bool);
466c02b4amuffinint	exp2c(tchar ***, bool);
476c02b4amuffintchar	*exp3(tchar ***, bool);
486c02b4amuffintchar	*exp3a(tchar ***, bool);
496c02b4amuffintchar	*exp4(tchar ***, bool);
506c02b4amuffintchar	*exp5(tchar ***, bool);
516c02b4amuffintchar	*exp6(tchar ***, bool);
526c02b4amuffinvoid	evalav(tchar **);
536c02b4amuffin
547c478bdstevel@tonic-gate/*
557c478bdstevel@tonic-gate * Determine if file given by name is accessible with permissions
567c478bdstevel@tonic-gate * given by mode.
577c478bdstevel@tonic-gate *
587c478bdstevel@tonic-gate * Borrowed from the Bourne sh, and modified a bit
597c478bdstevel@tonic-gate *
607c478bdstevel@tonic-gate * If the requested access  is  permitted,  a  value  of  0  is
617c478bdstevel@tonic-gate * returned.  Otherwise, a value of -1 is returned and errno is
627c478bdstevel@tonic-gate * set to indicate the error
637c478bdstevel@tonic-gate */
647c478bdstevel@tonic-gate
656c02b4amuffinint
666c02b4amuffinchk_access(tchar *path, mode_t mode)
6765b0c20nakanon{
687c478bdstevel@tonic-gate	static int flag;
6965b0c20nakanon	static uid_t euid;
707c478bdstevel@tonic-gate	struct stat statb;
717c478bdstevel@tonic-gate	mode_t ftype;
727c478bdstevel@tonic-gate	unsigned char name[MAXPATHLEN*MB_LEN_MAX]; /* General use buffer. */
737c478bdstevel@tonic-gate
747c478bdstevel@tonic-gate	/* convert tchar * to char * */
757c478bdstevel@tonic-gate	tstostr(name, path);
7665b0c20nakanon
7765b0c20nakanon	if (flag == 0) {
787c478bdstevel@tonic-gate		euid = geteuid();
797c478bdstevel@tonic-gate		flag = 1;
807c478bdstevel@tonic-gate	}
817c478bdstevel@tonic-gate	if (stat((char *)name, &statb) == 0) {
827c478bdstevel@tonic-gate		ftype = statb.st_mode & S_IFMT;
8365b0c20nakanon		if (access((char *)name, 010|(mode>>6)) == 0) {
8465b0c20nakanon			if (euid == 0) {
857c478bdstevel@tonic-gate				if (ftype != S_IFREG || mode != S_IEXEC)
8665b0c20nakanon					return (0);
8765b0c20nakanon				/* root can execute file as long as it has execute
8865b0c20nakanon				permission for someone */
897c478bdstevel@tonic-gate				if (statb.st_mode & (S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6)))
9065b0c20nakanon					return (0);
9165b0c20nakanon				return (-1);
927c478bdstevel@tonic-gate			}
9365b0c20nakanon			return (0);
947c478bdstevel@tonic-gate		}
957c478bdstevel@tonic-gate	}
9665b0c20nakanon	return (-1);
977c478bdstevel@tonic-gate}
987c478bdstevel@tonic-gate
996c02b4amuffinint
1006c02b4amuffinexp(tchar ***vp)
1017c478bdstevel@tonic-gate{
1027c478bdstevel@tonic-gate#ifdef TRACE
1037c478bdstevel@tonic-gate	tprintf("TRACE- exp()\n");
1047c478bdstevel@tonic-gate#endif
1057c478bdstevel@tonic-gate
1067c478bdstevel@tonic-gate	return (exp0(vp, 0));
1077c478bdstevel@tonic-gate}
1087c478bdstevel@tonic-gate
1096c02b4amuffinint
1106c02b4amuffinexp0(tchar ***vp, bool ignore)
1117c478bdstevel@tonic-gate{
1126c02b4amuffin	int p1 = exp1(vp, ignore);
1137c478bdstevel@tonic-gate#ifdef TRACE
1147c478bdstevel@tonic-gate	tprintf("TRACE- exp0()\n");
1157c478bdstevel@tonic-gate#endif
11665b0c20nakanon
1177c478bdstevel@tonic-gate#ifdef EDEBUG
1187c478bdstevel@tonic-gate	etraci("exp0 p1", p1, vp);
1197c478bdstevel@tonic-gate#endif
12065b0c20nakanon	if (**vp && eq(**vp, S_BARBAR /* "||" */)) {
1216c02b4amuffin		int p2;
1227c478bdstevel@tonic-gate
1237c478bdstevel@tonic-gate		(*vp)++;
1247c478bdstevel@tonic-gate		p2 = exp0(vp, (ignore&IGNORE) || p1);
1257c478bdstevel@tonic-gate#ifdef EDEBUG
1267c478bdstevel@tonic-gate		etraci("exp0 p2", p2, vp);
1277c478bdstevel@tonic-gate#endif
1287c478bdstevel@tonic-gate		return (p1 || p2);
1297c478bdstevel@tonic-gate	}
1307c478bdstevel@tonic-gate	return (p1);
1317c478bdstevel@tonic-gate}
1327c478bdstevel@tonic-gate
1336c02b4amuffinint
1346c02b4amuffinexp1(tchar ***vp, bool ignore)
1357c478bdstevel@tonic-gate{
1366c02b4amuffin	int p1 = exp2(vp, ignore);
1377c478bdstevel@tonic-gate
1387c478bdstevel@tonic-gate#ifdef TRACE
1397c478bdstevel@tonic-gate	tprintf("TRACE- exp1()\n");
1407c478bdstevel@tonic-gate#endif
1417c478bdstevel@tonic-gate#ifdef EDEBUG
1427c478bdstevel@tonic-gate	etraci("exp1 p1", p1, vp);
1437c478bdstevel@tonic-gate#endif
14465b0c20nakanon	if (**vp && eq(**vp, S_ANDAND /* "&&" */)) {
1456c02b4amuffin		int p2;
1467c478bdstevel@tonic-gate
1477c478bdstevel@tonic-gate		(*vp)++;
1487c478bdstevel@tonic-gate		p2 = exp1(vp, (ignore&IGNORE) || !p1);
1497c478bdstevel@tonic-gate#ifdef EDEBUG
1507c478bdstevel@tonic-gate		etraci("exp1 p2", p2, vp);
1517c478bdstevel@tonic-gate#endif
1527c478bdstevel@tonic-gate		return (p1 && p2);
1537c478bdstevel@tonic-gate	}
1547c478bdstevel@tonic-gate	return (p1);
1557c478bdstevel@tonic-gate}
1567c478bdstevel@tonic-gate
1576c02b4amuffinint
1586c02b4amuffinexp2(tchar ***vp, bool ignore)
1597c478bdstevel@tonic-gate{
1606c02b4amuffin	int p1 = exp2a(vp, ignore);
1617c478bdstevel@tonic-gate
1627c478bdstevel@tonic-gate#ifdef TRACE
1637c478bdstevel@tonic-gate	tprintf("TRACE- exp2()\n");
1647c478bdstevel@tonic-gate#endif
1657c478bdstevel@tonic-gate#ifdef EDEBUG
1667c478bdstevel@tonic-gate	etraci("exp3 p1", p1, vp);
1677c478bdstevel@tonic-gate#endif
16865b0c20nakanon	if (**vp && eq(**vp, S_BAR /* "|" */)) {
1696c02b4amuffin		int p2;
1707c478bdstevel@tonic-gate
1717c478bdstevel@tonic-gate		(*vp)++;
1727c478bdstevel@tonic-gate		p2 = exp2(vp, ignore);
1737c478bdstevel@tonic-gate#ifdef EDEBUG
1747c478bdstevel@tonic-gate		etraci("exp3 p2", p2, vp);
1757c478bdstevel@tonic-gate#endif
1767c478bdstevel@tonic-gate		return (p1 | p2);
1777c478bdstevel@tonic-gate	}
1787c478bdstevel@tonic-gate	return (p1);
1797c478bdstevel@tonic-gate}
1807c478bdstevel@tonic-gate
1816c02b4amuffinint
1826c02b4amuffinexp2a(tchar ***vp, bool ignore)
1837c478bdstevel@tonic-gate{
1846c02b4amuffin	int p1 = exp2b(vp, ignore);
1857c478bdstevel@tonic-gate
1867c478bdstevel@tonic-gate#ifdef TRACE
1877c478bdstevel@tonic-gate	tprintf("TRACE- exp2a()\n");
1887c478bdstevel@tonic-gate#endif
1897c478bdstevel@tonic-gate#ifdef EDEBUG
1907c478bdstevel@tonic-gate	etraci("exp2a p1", p1, vp);
1917c478bdstevel@tonic-gate#endif
19265b0c20nakanon	if (**vp && eq(**vp, S_HAT /* "^" */)) {
1936c02b4amuffin		int p2;
1947c478bdstevel@tonic-gate
1957c478bdstevel@tonic-gate		(*vp)++;
1967c478bdstevel@tonic-gate		p2 = exp2a(vp, ignore);
1977c478bdstevel@tonic-gate#ifdef EDEBUG
1987c478bdstevel@tonic-gate		etraci("exp2a p2", p2, vp);
1997c478bdstevel@tonic-gate#endif
2007c478bdstevel@tonic-gate		return (p1 ^ p2);
2017c478bdstevel@tonic-gate	}
2027c478bdstevel@tonic-gate	return (p1);
2037c478bdstevel@tonic-gate}
2047c478bdstevel@tonic-gate
2056c02b4amuffinint
2066c02b4amuffinexp2b(tchar ***vp, bool ignore)
2077c478bdstevel@tonic-gate{
2086c02b4amuffin	int p1 = exp2c(vp, ignore);
2097c478bdstevel@tonic-gate
2107c478bdstevel@tonic-gate#ifdef TRACE
2117c478bdstevel@tonic-gate	tprintf("TRACE- exp2b()\n");
2127c478bdstevel@tonic-gate#endif
2137c478bdstevel@tonic-gate#ifdef EDEBUG
2147c478bdstevel@tonic-gate	etraci("exp2b p1", p1, vp);
2157c478bdstevel@tonic-gate#endif
21665b0c20nakanon	if (**vp && eq(**vp, S_AND /* "&" */)) {
21765b0c20nakanon		int p2;
2187c478bdstevel@tonic-gate
2197c478bdstevel@tonic-gate		(*vp)++;
2207c478bdstevel@tonic-gate		p2 = exp2b(vp, ignore);
2217c478bdstevel@tonic-gate#ifdef EDEBUG
2227c478bdstevel@tonic-gate		etraci("exp2b p2", p2, vp);
2237c478bdstevel@tonic-gate#endif
2247c478bdstevel@tonic-gate		return (p1 & p2);
2257c478bdstevel@tonic-gate	}
2267c478bdstevel@tonic-gate	return (p1);
2277c478bdstevel@tonic-gate}
2287c478bdstevel@tonic-gate
2296c02b4amuffinint
2306c02b4amuffinexp2c(tchar ***vp, bool ignore)
2317c478bdstevel@tonic-gate{
2326c02b4amuffin	tchar *p1 = exp3(vp, ignore);
2336c02b4amuffin	tchar *p2;
2346c02b4amuffin	int i;
2357c478bdstevel@tonic-gate
2367c478bdstevel@tonic-gate#ifdef TRACE
2377c478bdstevel@tonic-gate	tprintf("TRACE- exp2c()\n");
2387c478bdstevel@tonic-gate#endif
2397c478bdstevel@tonic-gate#ifdef EDEBUG
2407c478bdstevel@tonic-gate	etracc("exp2c p1", p1, vp);
2417c478bdstevel@tonic-gate#endif
2427c478bdstevel@tonic-gate	if (i = isa(**vp, EQOP)) {
2437c478bdstevel@tonic-gate		(*vp)++;
2447c478bdstevel@tonic-gate		if (i == EQMATCH || i == NOTEQMATCH)
2457c478bdstevel@tonic-gate			ignore |= NOGLOB;
2467c478bdstevel@tonic-gate		p2 = exp3(vp, ignore);
2477c478bdstevel@tonic-gate#ifdef EDEBUG
2487c478bdstevel@tonic-gate		etracc("exp2c p2", p2, vp);
2497c478bdstevel@tonic-gate#endif
2507c478bdstevel@tonic-gate		if (!(ignore&IGNORE)) switch (i) {
2517c478bdstevel@tonic-gate
2527c478bdstevel@tonic-gate		case EQEQ:
2537c478bdstevel@tonic-gate			i = eq(p1, p2);
2547c478bdstevel@tonic-gate			break;
2557c478bdstevel@tonic-gate
2567c478bdstevel@tonic-gate		case NOTEQ:
2577c478bdstevel@tonic-gate			i = !eq(p1, p2);
2587c478bdstevel@tonic-gate			break;
2597c478bdstevel@tonic-gate
2607c478bdstevel@tonic-gate		case EQMATCH:
2617c478bdstevel@tonic-gate			i = Gmatch(p1, p2);
2627c478bdstevel@tonic-gate			break;
2637c478bdstevel@tonic-gate
2647c478bdstevel@tonic-gate		case NOTEQMATCH:
2657c478bdstevel@tonic-gate			i = !Gmatch(p1, p2);
2667c478bdstevel@tonic-gate			break;
2677c478bdstevel@tonic-gate		}
2687c478bdstevel@tonic-gate		xfree(p1), xfree(p2);
2697c478bdstevel@tonic-gate		return (i);
2707c478bdstevel@tonic-gate	}
2717c478bdstevel@tonic-gate	i = egetn(p1);
2727c478bdstevel@tonic-gate	xfree(p1);
2737c478bdstevel@tonic-gate	return (i);
2747c478bdstevel@tonic-gate}
2757c478bdstevel@tonic-gate
2767c478bdstevel@tonic-gatetchar *
2776c02b4amuffinexp3(tchar ***vp, bool ignore)
2787c478bdstevel@tonic-gate{
2796c02b4amuffin	tchar *p1, *p2;
2806c02b4amuffin	int i;
2817c478bdstevel@tonic-gate
2827c478bdstevel@tonic-gate#ifdef TRACE
2837c478bdstevel@tonic-gate	tprintf("TRACE- exp3()\n");
2847c478bdstevel@tonic-gate#endif
2857c478bdstevel@tonic-gate	p1 = exp3a(vp, ignore);
2867c478bdstevel@tonic-gate#ifdef EDEBUG
2877c478bdstevel@tonic-gate	etracc("exp3 p1", p1, vp);
2887c478bdstevel@tonic-gate#endif
2897c478bdstevel@tonic-gate	if (i = isa(**vp, RELOP)) {
2907c478bdstevel@tonic-gate		(*vp)++;
29165b0c20nakanon		if (**vp && eq(**vp, S_EQ /* "=" */))
2927c478bdstevel@tonic-gate			i |= 1, (*vp)++;
2937c478bdstevel@tonic-gate		p2 = exp3(vp, ignore);
2947c478bdstevel@tonic-gate#ifdef EDEBUG
2957c478bdstevel@tonic-gate		etracc("exp3 p2", p2, vp);
2967c478bdstevel@tonic-gate#endif
2977c478bdstevel@tonic-gate		if (!(ignore&IGNORE)) switch (i) {
2987c478bdstevel@tonic-gate
2997c478bdstevel@tonic-gate		case GTR:
3007c478bdstevel@tonic-gate			i = egetn(p1) > egetn(p2);
3017c478bdstevel@tonic-gate			break;
3027c478bdstevel@tonic-gate
3037c478bdstevel@tonic-gate		case GTR|1:
3047c478bdstevel@tonic-gate			i = egetn(p1) >= egetn(p2);
3057c478bdstevel@tonic-gate			break;
3067c478bdstevel@tonic-gate
3077c478bdstevel@tonic-gate		case LSS:
3087c478bdstevel@tonic-gate			i = egetn(p1) < egetn(p2);
3097c478bdstevel@tonic-gate			break;
3107c478bdstevel@tonic-gate
3117c478bdstevel@tonic-gate		case LSS|1:
3127c478bdstevel@tonic-gate			i = egetn(p1) <= egetn(p2);
3137c478bdstevel@tonic-gate			break;
3147c478bdstevel@tonic-gate		}
3157c478bdstevel@tonic-gate		xfree(p1), xfree(p2);
3167c478bdstevel@tonic-gate		return (putn(i));
3177c478bdstevel@tonic-gate	}
3187c478bdstevel@tonic-gate	return (p1);
3197c478bdstevel@tonic-gate}
3207c478bdstevel@tonic-gate
3217c478bdstevel@tonic-gatetchar *
3226c02b4amuffinexp3a(tchar ***vp, bool ignore)
3237c478bdstevel@tonic-gate{
3246c02b4amuffin	tchar *p1, *p2, *op;
3256c02b4amuffin	int i;
3267c478bdstevel@tonic-gate
3277c478bdstevel@tonic-gate#ifdef TRACE
3287c478bdstevel@tonic-gate	tprintf("TRACE- exp3a()\n");
3297c478bdstevel@tonic-gate#endif
3307c478bdstevel@tonic-gate	p1 = exp4(vp, ignore);
3317c478bdstevel@tonic-gate#ifdef EDEBUG
3327c478bdstevel@tonic-gate	etracc("exp3a p1", p1, vp);
3337c478bdstevel@tonic-gate#endif
3347c478bdstevel@tonic-gate	op = **vp;
3357c478bdstevel@tonic-gate	/* if (op && any(op[0], "<>") && op[0] == op[1]) { */
3367c478bdstevel@tonic-gate	if (op && (op[0] == '<' || op[0] == '>') && op[0] == op[1]) {
3377c478bdstevel@tonic-gate		(*vp)++;
3387c478bdstevel@tonic-gate		p2 = exp3a(vp, ignore);
3397c478bdstevel@tonic-gate#ifdef EDEBUG
3407c478bdstevel@tonic-gate		etracc("exp3a p2", p2, vp);
3417c478bdstevel@tonic-gate#endif
3427c478bdstevel@tonic-gate		if (op[0] == '<')
3437c478bdstevel@tonic-gate			i = egetn(p1) << egetn(p2);
3447c478bdstevel@tonic-gate		else
3457c478bdstevel@tonic-gate			i = egetn(p1) >> egetn(p2);
3467c478bdstevel@tonic-gate		xfree(p1), xfree(p2);
3477c478bdstevel@tonic-gate		return (putn(i));
3487c478bdstevel@tonic-gate	}
3497c478bdstevel@tonic-gate	return (p1);
3507c478bdstevel@tonic-gate}
3517c478bdstevel@tonic-gate
3527c478bdstevel@tonic-gatetchar *
3536c02b4amuffinexp4(tchar ***vp, bool ignore)
3547c478bdstevel@tonic-gate{
3556c02b4amuffin	tchar *p1, *p2;
3566c02b4amuffin	int i = 0;
3577c478bdstevel@tonic-gate
3587c478bdstevel@tonic-gate#ifdef TRACE
3597c478bdstevel@tonic-gate	tprintf("TRACE- exp4()\n");
3607c478bdstevel@tonic-gate#endif
3617c478bdstevel@tonic-gate	p1 = exp5(vp, ignore);
3627c478bdstevel@tonic-gate#ifdef EDEBUG
3637c478bdstevel@tonic-gate	etracc("exp4 p1", p1, vp);
3647c478bdstevel@tonic-gate#endif
3657c478bdstevel@tonic-gate	if (isa(**vp, ADDOP)) {
3666c02b4amuffin		tchar *op = *(*vp)++;
3677c478bdstevel@tonic-gate
3687c478bdstevel@tonic-gate		p2 = exp4(vp, ignore);
3697c478bdstevel@tonic-gate#ifdef EDEBUG
3707c478bdstevel@tonic-gate		etracc("exp4 p2", p2, vp);
3717c478bdstevel@tonic-gate#endif
3727c478bdstevel@tonic-gate		if (!(ignore&IGNORE)) switch (op[0]) {
3737c478bdstevel@tonic-gate
3747c478bdstevel@tonic-gate		case '+':
3757c478bdstevel@tonic-gate			i = egetn(p1) + egetn(p2);
3767c478bdstevel@tonic-gate			break;
3777c478bdstevel@tonic-gate
3787c478bdstevel@tonic-gate		case '-':
3797c478bdstevel@tonic-gate			i = egetn(p1) - egetn(p2);
3807c478bdstevel@tonic-gate			break;
3817c478bdstevel@tonic-gate		}
3827c478bdstevel@tonic-gate		xfree(p1), xfree(p2);
3837c478bdstevel@tonic-gate		return (putn(i));
3847c478bdstevel@tonic-gate	}
3857c478bdstevel@tonic-gate	return (p1);
3867c478bdstevel@tonic-gate}
3877c478bdstevel@tonic-gate
3887c478bdstevel@tonic-gatetchar *
3896c02b4amuffinexp5(tchar ***vp, bool ignore)
3907c478bdstevel@tonic-gate{
3916c02b4amuffin	tchar *p1, *p2;
3926c02b4amuffin	int i = 0;
3937c478bdstevel@tonic-gate
3947c478bdstevel@tonic-gate#ifdef TRACE
3957c478bdstevel@tonic-gate	tprintf("TRACE- exp5()\n");
3967c478bdstevel@tonic-gate#endif
3977c478bdstevel@tonic-gate	p1 = exp6(vp, ignore);
3987c478bdstevel@tonic-gate#ifdef EDEBUG
3997c478bdstevel@tonic-gate	etracc("exp5 p1", p1, vp);
4007c478bdstevel@tonic-gate#endif
4017c478bdstevel@tonic-gate	if (isa(**vp, MULOP)) {
4026c02b4amuffin		tchar *op = *(*vp)++;
4037c478bdstevel@tonic-gate
4047c478bdstevel@tonic-gate		p2 = exp5(vp, ignore);
4057c478bdstevel@tonic-gate#ifdef EDEBUG
4067c478bdstevel@tonic-gate		etracc("exp5 p2", p2, vp);
4077c478bdstevel@tonic-gate#endif
4087c478bdstevel@tonic-gate		if (!(ignore&IGNORE)) switch (op[0]) {
4097c478bdstevel@tonic-gate
4107c478bdstevel@tonic-gate		case '*':
4117c478bdstevel@tonic-gate			i = egetn(p1) * egetn(p2);
4127c478bdstevel@tonic-gate			break;
4137c478bdstevel@tonic-gate
4147c478bdstevel@tonic-gate		case '/':
4157c478bdstevel@tonic-gate			i = egetn(p2);
4167c478bdstevel@tonic-gate			if (i == 0)
4177c478bdstevel@tonic-gate				error("Divide by 0");
4187c478bdstevel@tonic-gate			i = egetn(p1) / i;
4197c478bdstevel@tonic-gate			break;
4207c478bdstevel@tonic-gate
4217c478bdstevel@tonic-gate		case '%':
4227c478bdstevel@tonic-gate			i = egetn(p2);
4237c478bdstevel@tonic-gate			if (i == 0)
4247c478bdstevel@tonic-gate				error("Mod by 0");
4257c478bdstevel@tonic-gate			i = egetn(p1) % i;
4267c478bdstevel@tonic-gate			break;
4277c478bdstevel@tonic-gate		}
4287c478bdstevel@tonic-gate		xfree(p1), xfree(p2);
4297c478bdstevel@tonic-gate		return (putn(i));
4307c478bdstevel@tonic-gate	}
4317c478bdstevel@tonic-gate	return (p1);
4327c478bdstevel@tonic-gate}
4337c478bdstevel@tonic-gate
4347c478bdstevel@tonic-gatetchar *
4356c02b4amuffinexp6(tchar ***vp, bool ignore)
4367c478bdstevel@tonic-gate{
4377c478bdstevel@tonic-gate	int ccode, i;
4386c02b4amuffin	tchar *cp, *dp, *ep;
4397c478bdstevel@tonic-gate
4407c478bdstevel@tonic-gate#ifdef TRACE
4417c478bdstevel@tonic-gate	tprintf("TRACE- exp6()\n");
4427c478bdstevel@tonic-gate#endif
4437c478bdstevel@tonic-gate	if (**vp == 0)
4447c478bdstevel@tonic-gate		bferr("Expression syntax");
4457c478bdstevel@tonic-gate	if (eq(**vp, S_EXAS /* "!" */)) {
4467c478bdstevel@tonic-gate		(*vp)++;
4477c478bdstevel@tonic-gate		cp = exp6(vp, ignore);
4487c478bdstevel@tonic-gate#ifdef EDEBUG
4497c478bdstevel@tonic-gate		etracc("exp6 ! cp", cp, vp);
4507c478bdstevel@tonic-gate#endif
4517c478bdstevel@tonic-gate		i = egetn(cp);
4527c478bdstevel@tonic-gate		xfree(cp);
4537c478bdstevel@tonic-gate		return (putn(!i));
4547c478bdstevel@tonic-gate	}
45565b0c20nakanon	if (eq(**vp, S_TIL /* "~" */)) {
4567c478bdstevel@tonic-gate		(*vp)++;
4577c478bdstevel@tonic-gate		cp = exp6(vp, ignore);
4587c478bdstevel@tonic-gate#ifdef EDEBUG
4597c478bdstevel@tonic-gate		etracc("exp6 ~ cp", cp, vp);
4607c478bdstevel@tonic-gate#endif
4617c478bdstevel@tonic-gate		i = egetn(cp);
4627c478bdstevel@tonic-gate		xfree(cp);
4637c478bdstevel@tonic-gate		return (putn(~i));
4647c478bdstevel@tonic-gate	}
46565b0c20nakanon	if (eq(**vp, S_LPAR /* "(" */)) {
4667c478bdstevel@tonic-gate		(*vp)++;
4677c478bdstevel@tonic-gate		ccode = exp0(vp, ignore);
4687c478bdstevel@tonic-gate#ifdef EDEBUG
4697c478bdstevel@tonic-gate		etraci("exp6 () ccode", ccode, vp);
4707c478bdstevel@tonic-gate#endif
4717c478bdstevel@tonic-gate		if (*vp == 0 || **vp == 0 || ***vp != ')')
4727c478bdstevel@tonic-gate			bferr("Expression syntax");
4737c478bdstevel@tonic-gate		(*vp)++;
4747c478bdstevel@tonic-gate		return (putn(ccode));
4757c478bdstevel@tonic-gate	}
4767c478bdstevel@tonic-gate	if (eq(**vp, S_LBRA /* "{" */)) {
4776c02b4amuffin		tchar **v;
4787c478bdstevel@tonic-gate		struct command faket;
4797c478bdstevel@tonic-gate		tchar *fakecom[2];
4807c478bdstevel@tonic-gate
4817c478bdstevel@tonic-gate		faket.t_dtyp = TCOM;
4827c478bdstevel@tonic-gate		faket.t_dflg = 0;
4837c478bdstevel@tonic-gate		faket.t_dcar = faket.t_dcdr = faket.t_dspr = (struct command *)0;
4847c478bdstevel@tonic-gate		faket.t_dcom = fakecom;
48565b0c20nakanon		fakecom[0] = S_BRAPPPBRA /* "{ ... }" */;
4867c478bdstevel@tonic-gate		fakecom[1] = NOSTR;
4877c478bdstevel@tonic-gate		(*vp)++;
4887c478bdstevel@tonic-gate		v = *vp;
4897c478bdstevel@tonic-gate		for (;;) {
4907c478bdstevel@tonic-gate			if (!**vp)
4917c478bdstevel@tonic-gate				bferr("Missing }");
49265b0c20nakanon			if (eq(*(*vp)++, S_RBRA /* "}" */))
4937c478bdstevel@tonic-gate				break;
4947c478bdstevel@tonic-gate		}
4957c478bdstevel@tonic-gate		if (ignore&IGNORE)
49665b0c20nakanon			return (S_ /* "" */);
4977c478bdstevel@tonic-gate		psavejob();
4987c478bdstevel@tonic-gate		if (pfork(&faket, -1) == 0) {
4997c478bdstevel@tonic-gate			*--(*vp) = 0;
5007c478bdstevel@tonic-gate			evalav(v);
5017c478bdstevel@tonic-gate			exitstat();
5027c478bdstevel@tonic-gate		}
5037c478bdstevel@tonic-gate		pwait();
5047c478bdstevel@tonic-gate		prestjob();
5057c478bdstevel@tonic-gate#ifdef EDEBUG
5067c478bdstevel@tonic-gate		etraci("exp6 {} status", egetn(value("status")), vp);
5077c478bdstevel@tonic-gate#endif
50865b0c20nakanon		return (putn(egetn(value(S_status /* "status" */)) == 0));
5097c478bdstevel@tonic-gate	}
5107c478bdstevel@tonic-gate	if (isa(**vp, ANYOP))
51165b0c20nakanon		return (S_ /* "" */);
5127c478bdstevel@tonic-gate	cp = *(*vp)++;
51365b0c20nakanon	if (*cp == '-' && any(cp[1], S_erwxfdzo /* "erwxfdzo" */)) {
5147c478bdstevel@tonic-gate		struct stat stb;
5157c478bdstevel@tonic-gate
5167c478bdstevel@tonic-gate		if (cp[2] != '\0')
5177c478bdstevel@tonic-gate			bferr("Malformed file inquiry");
5187c478bdstevel@tonic-gate
5197c478bdstevel@tonic-gate		/*
5207c478bdstevel@tonic-gate		 * Detect missing file names by checking for operator
5217c478bdstevel@tonic-gate		 * in the file name position.  However, if an operator
5227c478bdstevel@tonic-gate		 * name appears there, we must make sure that there's
5237c478bdstevel@tonic-gate		 * no file by that name (e.g., "/") before announcing
5247c478bdstevel@tonic-gate		 * an error.  Even this check isn't quite right, since
5257c478bdstevel@tonic-gate		 * it doesn't take globbing into account.
5267c478bdstevel@tonic-gate		 */
527fd5e982blu		if ((**vp == NULL) || isa(**vp, ANYOP) && stat_(**vp, &stb))
5287c478bdstevel@tonic-gate			bferr("Missing file name");
5297c478bdstevel@tonic-gate		dp = *(*vp)++;
5307c478bdstevel@tonic-gate
5317c478bdstevel@tonic-gate		if (ignore&IGNORE)
53265b0c20nakanon			return (S_ /* "" */);
5337c478bdstevel@tonic-gate		ep = globone(dp);
5347c478bdstevel@tonic-gate		switch (cp[1]) {
5357c478bdstevel@tonic-gate
5367c478bdstevel@tonic-gate		case 'r':
5377c478bdstevel@tonic-gate			i = !chk_access(ep, S_IREAD);
5387c478bdstevel@tonic-gate			break;
5397c478bdstevel@tonic-gate
5407c478bdstevel@tonic-gate		case 'w':
5417c478bdstevel@tonic-gate			i = !chk_access(ep, S_IWRITE);
5427c478bdstevel@tonic-gate			break;
5437c478bdstevel@tonic-gate
5447c478bdstevel@tonic-gate		case 'x':
5457c478bdstevel@tonic-gate			i = !chk_access(ep, S_IEXEC);
5467c478bdstevel@tonic-gate			break;
5477c478bdstevel@tonic-gate
5487c478bdstevel@tonic-gate		default:
5497c478bdstevel@tonic-gate			if (stat_(ep, &stb)) {
5507c478bdstevel@tonic-gate				xfree(ep);
55165b0c20nakanon				return (S_0 /* "0" */);
5527c478bdstevel@tonic-gate			}
5537c478bdstevel@tonic-gate			switch (cp[1]) {
5547c478bdstevel@tonic-gate
5557c478bdstevel@tonic-gate			case 'f':
5567c478bdstevel@tonic-gate				i = (stb.st_mode & S_IFMT) == S_IFREG;
5577c478bdstevel@tonic-gate				break;
5587c478bdstevel@tonic-gate
5597c478bdstevel@tonic-gate			case 'd':
5607c478bdstevel@tonic-gate				i = (stb.st_mode & S_IFMT) == S_IFDIR;
5617c478bdstevel@tonic-gate				break;
5627c478bdstevel@tonic-gate
5637c478bdstevel@tonic-gate			case 'z':
5647c478bdstevel@tonic-gate				i = stb.st_size == 0;
5657c478bdstevel@tonic-gate				break;
5667c478bdstevel@tonic-gate
5677c478bdstevel@tonic-gate			case 'e':
5687c478bdstevel@tonic-gate				i = 1;
5697c478bdstevel@tonic-gate				break;
5707c478bdstevel@tonic-gate
5717c478bdstevel@tonic-gate			case 'o':
5727c478bdstevel@tonic-gate				i = stb.st_uid == uid;
5737c478bdstevel@tonic-gate				break;
5747c478bdstevel@tonic-gate			}
5757c478bdstevel@tonic-gate		}
5767c478bdstevel@tonic-gate#ifdef EDEBUG
5777c478bdstevel@tonic-gate		etraci("exp6 -? i", i, vp);
5787c478bdstevel@tonic-gate#endif
5797c478bdstevel@tonic-gate		xfree(ep);
5807c478bdstevel@tonic-gate		return (putn(i));
5817c478bdstevel@tonic-gate	}
5827c478bdstevel@tonic-gate#ifdef EDEBUG
5837c478bdstevel@tonic-gate	etracc("exp6 default", cp, vp);
5847c478bdstevel@tonic-gate#endif
5857c478bdstevel@tonic-gate	return (ignore&NOGLOB ? savestr(cp) : globone(cp));
5867c478bdstevel@tonic-gate}
5877c478bdstevel@tonic-gate
5886c02b4amuffinvoid
5896c02b4amuffinevalav(tchar **v)
5907c478bdstevel@tonic-gate{
5917c478bdstevel@tonic-gate	struct wordent paraml;
5926c02b4amuffin	struct wordent *hp = &paraml;
5937c478bdstevel@tonic-gate	struct command *t;
5946c02b4amuffin	struct wordent *wdp = hp;
59565b0c20nakanon
5967c478bdstevel@tonic-gate#ifdef TRACE
5977c478bdstevel@tonic-gate	tprintf("TRACE- evalav()\n");
5987c478bdstevel@tonic-gate#endif
59965b0c20nakanon	set(S_status /* "status" */, S_0 /* "0" */);
6007c478bdstevel@tonic-gate	hp->prev = hp->next = hp;
60165b0c20nakanon	hp->word = S_ /* "" */;
6027c478bdstevel@tonic-gate	while (*v) {
60365b0c20nakanon		struct wordent *new = (struct wordent *)xcalloc(1, sizeof *wdp);
6047c478bdstevel@tonic-gate
6057c478bdstevel@tonic-gate		new->prev = wdp;
6067c478bdstevel@tonic-gate		new->next = hp;
6077c478bdstevel@tonic-gate		wdp->next = new;
6087c478bdstevel@tonic-gate		wdp = new;
6097c478bdstevel@tonic-gate		wdp->word = savestr(*v++);
6107c478bdstevel@tonic-gate	}
6117c478bdstevel@tonic-gate	hp->prev = wdp;
6127c478bdstevel@tonic-gate	alias(&paraml);
6137c478bdstevel@tonic-gate	t = syntax(paraml.next, &paraml, 0);
6147c478bdstevel@tonic-gate	if (err)
6157c478bdstevel@tonic-gate		error("%s", gettext(err));
6167c478bdstevel@tonic-gate	execute(t, -1);
6177c478bdstevel@tonic-gate	freelex(&paraml), freesyn(t);
6187c478bdstevel@tonic-gate}
6197c478bdstevel@tonic-gate
6206c02b4amuffinint
6216c02b4amuffinisa(tchar *cp, int what)
6227c478bdstevel@tonic-gate{
6237c478bdstevel@tonic-gate
6247c478bdstevel@tonic-gate#ifdef TRACE
6257c478bdstevel@tonic-gate	tprintf("TRACE- isa()\n");
6267c478bdstevel@tonic-gate#endif
6277c478bdstevel@tonic-gate	if (cp == 0)
6287c478bdstevel@tonic-gate		return ((what & RESTOP) != 0);
6297c478bdstevel@tonic-gate	if (cp[1] == 0) {
6307c478bdstevel@tonic-gate		if (what & ADDOP && (*cp == '+' || *cp == '-'))
6317c478bdstevel@tonic-gate			return (1);
6327c478bdstevel@tonic-gate		if (what & MULOP && (*cp == '*' || *cp == '/' || *cp == '%'))
6337c478bdstevel@tonic-gate			return (1);
6347c478bdstevel@tonic-gate		if (what & RESTOP && (*cp == '(' || *cp == ')' || *cp == '!' ||
63565b0c20nakanon					*cp == '~' || *cp == '^' || *cp == '"'))
6367c478bdstevel@tonic-gate			return (1);
6377c478bdstevel@tonic-gate	} else if (cp[2] == 0) {
6387c478bdstevel@tonic-gate		if (what & RESTOP) {
6397c478bdstevel@tonic-gate			if (cp[0] == '|' && cp[1] == '&')
6407c478bdstevel@tonic-gate				return (1);
6417c478bdstevel@tonic-gate			if (cp[0] == '<' && cp[1] == '<')
6427c478bdstevel@tonic-gate				return (1);
6437c478bdstevel@tonic-gate			if (cp[0] == '>' && cp[1] == '>')
6447c478bdstevel@tonic-gate				return (1);
6457c478bdstevel@tonic-gate		}
6467c478bdstevel@tonic-gate		if (what & EQOP) {
6477c478bdstevel@tonic-gate			if (cp[0] == '=') {
6487c478bdstevel@tonic-gate				if (cp[1] == '=')
6497c478bdstevel@tonic-gate					return (EQEQ);
6507c478bdstevel@tonic-gate				if (cp[1] == '~')
6517c478bdstevel@tonic-gate					return (EQMATCH);
6527c478bdstevel@tonic-gate			} else if (cp[0] == '!') {
6537c478bdstevel@tonic-gate				if (cp[1] == '=')
6547c478bdstevel@tonic-gate					return (NOTEQ);
6557c478bdstevel@tonic-gate				if (cp[1] == '~')
6567c478bdstevel@tonic-gate					return (NOTEQMATCH);
6577c478bdstevel@tonic-gate			}
6587c478bdstevel@tonic-gate		}
6597c478bdstevel@tonic-gate	}
6607c478bdstevel@tonic-gate	if (what & RELOP) {
6617c478bdstevel@tonic-gate		if (*cp == '<')
6627c478bdstevel@tonic-gate			return (LSS);
6637c478bdstevel@tonic-gate		if (*cp == '>')
6647c478bdstevel@tonic-gate			return (GTR);
6657c478bdstevel@tonic-gate	}
6667c478bdstevel@tonic-gate	return (0);
6677c478bdstevel@tonic-gate}
6687c478bdstevel@tonic-gate
6696c02b4amuffinint
6706c02b4amuffinegetn(tchar *cp)
6717c478bdstevel@tonic-gate{
6727c478bdstevel@tonic-gate
6737c478bdstevel@tonic-gate#ifdef TRACE
6747c478bdstevel@tonic-gate	tprintf("TRACE- egetn()\n");
6757c478bdstevel@tonic-gate#endif
6767c478bdstevel@tonic-gate	if (*cp && *cp != '-' && !digit(*cp))
6777c478bdstevel@tonic-gate		bferr("Expression syntax");
6787c478bdstevel@tonic-gate	return (getn(cp));
6797c478bdstevel@tonic-gate}
6807c478bdstevel@tonic-gate
6817c478bdstevel@tonic-gate/* Phew! */
6827c478bdstevel@tonic-gate
6837c478bdstevel@tonic-gate#ifdef EDEBUG
6846c02b4amuffinvoid
6856c02b4amuffinetraci(tchar *str, int i, tchar ***vp)
6867c478bdstevel@tonic-gate{
6877c478bdstevel@tonic-gate
6887c478bdstevel@tonic-gate	printf("%s=%d\t", str, i);
6897c478bdstevel@tonic-gate	blkpr(*vp);
6907c478bdstevel@tonic-gate	printf("\n");
6917c478bdstevel@tonic-gate}
6927c478bdstevel@tonic-gate
6936c02b4amuffinvoid
6946c02b4amuffinetracc(tchar *str, tchar *cp, tchar ***vp)
6957c478bdstevel@tonic-gate{
6967c478bdstevel@tonic-gate
6977c478bdstevel@tonic-gate	printf("%s=%s\t", str, cp);
6987c478bdstevel@tonic-gate	blkpr(*vp);
6997c478bdstevel@tonic-gate	printf("\n");
7007c478bdstevel@tonic-gate}
7017c478bdstevel@tonic-gate#endif
702