xref: /freebsd/contrib/tcsh/sh.exp.c (revision 45e5710b)
145e5710bSMark Peek /*
2c80476e4SDavid E. O'Brien  * sh.exp.c: Expression evaluations
3c80476e4SDavid E. O'Brien  */
4c80476e4SDavid E. O'Brien /*-
5c80476e4SDavid E. O'Brien  * Copyright (c) 1980, 1991 The Regents of the University of California.
6c80476e4SDavid E. O'Brien  * All rights reserved.
7c80476e4SDavid E. O'Brien  *
8c80476e4SDavid E. O'Brien  * Redistribution and use in source and binary forms, with or without
9c80476e4SDavid E. O'Brien  * modification, are permitted provided that the following conditions
10c80476e4SDavid E. O'Brien  * are met:
11c80476e4SDavid E. O'Brien  * 1. Redistributions of source code must retain the above copyright
12c80476e4SDavid E. O'Brien  *    notice, this list of conditions and the following disclaimer.
13c80476e4SDavid E. O'Brien  * 2. Redistributions in binary form must reproduce the above copyright
14c80476e4SDavid E. O'Brien  *    notice, this list of conditions and the following disclaimer in the
15c80476e4SDavid E. O'Brien  *    documentation and/or other materials provided with the distribution.
16c80476e4SDavid E. O'Brien  * 3. Neither the name of the University nor the names of its contributors
1729301572SMark Peek  *    may be used to endorse or promote products derived from this software
18c80476e4SDavid E. O'Brien  *    without specific prior written permission.
19c80476e4SDavid E. O'Brien  *
20c80476e4SDavid E. O'Brien  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21c80476e4SDavid E. O'Brien  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22c80476e4SDavid E. O'Brien  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23c80476e4SDavid E. O'Brien  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24c80476e4SDavid E. O'Brien  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25c80476e4SDavid E. O'Brien  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26c80476e4SDavid E. O'Brien  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27c80476e4SDavid E. O'Brien  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28c80476e4SDavid E. O'Brien  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29c80476e4SDavid E. O'Brien  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30c80476e4SDavid E. O'Brien  * SUCH DAMAGE.
31c80476e4SDavid E. O'Brien  */
32c80476e4SDavid E. O'Brien #include "sh.h"
33c80476e4SDavid E. O'Brien #include "tw.h"
34c80476e4SDavid E. O'Brien 
3545e5710bSMark Peek /*
3629301572SMark Peek  * C shell
3729301572SMark Peek  */
38c80476e4SDavid E. O'Brien 
39c80476e4SDavid E. O'Brien #define TEXP_IGNORE 1	/* in ignore, it means to ignore value, just parse */
40c80476e4SDavid E. O'Brien #define TEXP_NOGLOB 2	/* in ignore, it means not to globone */
41c80476e4SDavid E. O'Brien 
42c80476e4SDavid E. O'Brien #define	ADDOP	1
43c80476e4SDavid E. O'Brien #define	MULOP	2
44c80476e4SDavid E. O'Brien #define	EQOP	4
45c80476e4SDavid E. O'Brien #define	RELOP	8
46c80476e4SDavid E. O'Brien #define	RESTOP	16
47c80476e4SDavid E. O'Brien #define	ANYOP	31
48c80476e4SDavid E. O'Brien 
49c80476e4SDavid E. O'Brien #define	EQEQ	1
50c80476e4SDavid E. O'Brien #define	GTR	2
51c80476e4SDavid E. O'Brien #define	LSS	4
52c80476e4SDavid E. O'Brien #define	NOTEQ	6
53c80476e4SDavid E. O'Brien #define EQMATCH 7
54c80476e4SDavid E. O'Brien #define NOTEQMATCH 8
55c80476e4SDavid E. O'Brien 
56c80476e4SDavid E. O'Brien static	int	   sh_access	(const Char *, int);
57c80476e4SDavid E. O'Brien static	tcsh_number_t  exp1		(Char ***, int);
58c80476e4SDavid E. O'Brien static	tcsh_number_t  exp2x	(Char ***, int);
59c80476e4SDavid E. O'Brien static	tcsh_number_t  exp2a	(Char ***, int);
6045e5710bSMark Peek static	tcsh_number_t  exp2b	(Char ***, int);
6145e5710bSMark Peek static	tcsh_number_t  exp2c	(Char ***, int);
6245e5710bSMark Peek static	Char 	  *exp3		(Char ***, int);
6345e5710bSMark Peek static	Char 	  *exp3a	(Char ***, int);
6445e5710bSMark Peek static	Char 	  *exp4		(Char ***, int);
6545e5710bSMark Peek static	Char 	  *exp5		(Char ***, int);
6645e5710bSMark Peek static	Char 	  *exp6		(Char ***, int);
6745e5710bSMark Peek static	void	   evalav	(Char **);
6845e5710bSMark Peek static	int	   isa		(Char *, int);
6945e5710bSMark Peek static	tcsh_number_t  egetn	(const Char *);
7045e5710bSMark Peek 
7145e5710bSMark Peek #ifdef EDEBUG
7245e5710bSMark Peek static	void	   etracc	(const char *, const Char *, Char ***);
7345e5710bSMark Peek static	void	   etraci	(const char *, tcsh_number_t, Char ***);
74c80476e4SDavid E. O'Brien #else /* !EDEBUG */
75c80476e4SDavid E. O'Brien #define etracc(A, B, C) ((void)0)
76c80476e4SDavid E. O'Brien #define etraci(A, B, C) ((void)0)
7745e5710bSMark Peek #endif /* !EDEBUG */
7845e5710bSMark Peek 
7945e5710bSMark Peek /*
8045e5710bSMark Peek  * shell access function according to POSIX and non POSIX
8145e5710bSMark Peek  * From Beto Appleton (beto@aixwiz.aix.ibm.com)
8245e5710bSMark Peek  */
83c80476e4SDavid E. O'Brien static int
sh_access(const Char * fname,int mode)84c80476e4SDavid E. O'Brien sh_access(const Char *fname, int mode)
85c80476e4SDavid E. O'Brien {
86c80476e4SDavid E. O'Brien #if defined(POSIX) && !defined(USE_ACCESS)
87c80476e4SDavid E. O'Brien     struct stat     statb;
88c80476e4SDavid E. O'Brien #endif /* POSIX */
89c80476e4SDavid E. O'Brien     char *name = short2str(fname);
9045e5710bSMark Peek 
91c80476e4SDavid E. O'Brien     if (*name == '\0')
92c80476e4SDavid E. O'Brien 	return 1;
93c80476e4SDavid E. O'Brien 
94c80476e4SDavid E. O'Brien #if !defined(POSIX) || defined(USE_ACCESS)
95c80476e4SDavid E. O'Brien     return access(name, mode);
96c80476e4SDavid E. O'Brien #else /* POSIX */
97c80476e4SDavid E. O'Brien 
98c80476e4SDavid E. O'Brien     /*
99c80476e4SDavid E. O'Brien      * POSIX 1003.2-d11.2
100c80476e4SDavid E. O'Brien      *	-r file		True if file exists and is readable.
101c80476e4SDavid E. O'Brien      *	-w file		True if file exists and is writable.
102c80476e4SDavid E. O'Brien      *			True shall indicate only that the write flag is on.
103c80476e4SDavid E. O'Brien      *			The file shall not be writable on a read-only file
104c80476e4SDavid E. O'Brien      *			system even if this test indicates true.
105c80476e4SDavid E. O'Brien      *	-x file		True if file exists and is executable.
106c80476e4SDavid E. O'Brien      *			True shall indicate only that the execute flag is on.
107c80476e4SDavid E. O'Brien      *			If file is a directory, true indicates that the file
108c80476e4SDavid E. O'Brien      *			can be searched.
109c80476e4SDavid E. O'Brien      */
110c80476e4SDavid E. O'Brien     if (mode != W_OK && mode != X_OK)
111c80476e4SDavid E. O'Brien 	return access(name, mode);
112c80476e4SDavid E. O'Brien 
113c80476e4SDavid E. O'Brien     if (stat(name, &statb) == -1)
114c80476e4SDavid E. O'Brien 	return 1;
115c80476e4SDavid E. O'Brien 
116c80476e4SDavid E. O'Brien     if (access(name, mode) == 0) {
117c80476e4SDavid E. O'Brien #ifdef S_ISDIR
118c80476e4SDavid E. O'Brien 	if (S_ISDIR(statb.st_mode) && mode == X_OK)
119c80476e4SDavid E. O'Brien 	    return 0;
120c80476e4SDavid E. O'Brien #endif /* S_ISDIR */
121c80476e4SDavid E. O'Brien 
122c80476e4SDavid E. O'Brien 	/* root needs permission for someone */
123c80476e4SDavid E. O'Brien 	switch (mode) {
124c80476e4SDavid E. O'Brien 	case W_OK:
125c80476e4SDavid E. O'Brien 	    mode = S_IWUSR | S_IWGRP | S_IWOTH;
126c80476e4SDavid E. O'Brien 	    break;
127c80476e4SDavid E. O'Brien 	case X_OK:
128c80476e4SDavid E. O'Brien 	    mode = S_IXUSR | S_IXGRP | S_IXOTH;
129c80476e4SDavid E. O'Brien 	    break;
130c80476e4SDavid E. O'Brien 	default:
131c80476e4SDavid E. O'Brien 	    abort();
132c80476e4SDavid E. O'Brien 	    break;
133c80476e4SDavid E. O'Brien 	}
134c80476e4SDavid E. O'Brien 
135c80476e4SDavid E. O'Brien     }
136c80476e4SDavid E. O'Brien 
137c80476e4SDavid E. O'Brien     else if (euid == statb.st_uid)
138c80476e4SDavid E. O'Brien 	mode <<= 6;
139c80476e4SDavid E. O'Brien 
140c80476e4SDavid E. O'Brien     else if (egid == statb.st_gid)
141c80476e4SDavid E. O'Brien 	mode <<= 3;
142c80476e4SDavid E. O'Brien 
143c80476e4SDavid E. O'Brien # ifdef NGROUPS_MAX
144c80476e4SDavid E. O'Brien     else {
145c80476e4SDavid E. O'Brien 	/* you can be in several groups */
146c80476e4SDavid E. O'Brien 	long	n;
147c80476e4SDavid E. O'Brien 	GETGROUPS_T *groups;
148c80476e4SDavid E. O'Brien 
149c80476e4SDavid E. O'Brien 	/*
150c80476e4SDavid E. O'Brien 	 * Try these things to find a positive maximum groups value:
151c80476e4SDavid E. O'Brien 	 *   1) sysconf(_SC_NGROUPS_MAX)
152c80476e4SDavid E. O'Brien 	 *   2) NGROUPS_MAX
15323338178SMark Peek 	 *   3) getgroups(0, unused)
154c80476e4SDavid E. O'Brien 	 * Then allocate and scan the groups array if one of these worked.
155c80476e4SDavid E. O'Brien 	 */
156c80476e4SDavid E. O'Brien #  if defined (HAVE_SYSCONF) && defined (_SC_NGROUPS_MAX)
157c80476e4SDavid E. O'Brien 	if ((n = sysconf(_SC_NGROUPS_MAX)) == -1)
158c80476e4SDavid E. O'Brien #  endif /* _SC_NGROUPS_MAX */
159c80476e4SDavid E. O'Brien 	    n = NGROUPS_MAX;
160c80476e4SDavid E. O'Brien 	if (n <= 0)
161c80476e4SDavid E. O'Brien 	    n = getgroups(0, (GETGROUPS_T *) NULL);
16223338178SMark Peek 
163c80476e4SDavid E. O'Brien 	if (n > 0) {
164c80476e4SDavid E. O'Brien 	    groups = xmalloc(n * sizeof(*groups));
165c80476e4SDavid E. O'Brien 	    n = getgroups((int) n, groups);
166c80476e4SDavid E. O'Brien 	    while (--n >= 0)
16723338178SMark Peek 		if (groups[n] == statb.st_gid) {
168c80476e4SDavid E. O'Brien 		    mode <<= 3;
169c80476e4SDavid E. O'Brien 		    break;
17045e5710bSMark Peek 		}
171c80476e4SDavid E. O'Brien 	    xfree(groups);
172c80476e4SDavid E. O'Brien 	}
173c80476e4SDavid E. O'Brien     }
174c80476e4SDavid E. O'Brien # endif /* NGROUPS_MAX */
175c80476e4SDavid E. O'Brien 
176c80476e4SDavid E. O'Brien     if (statb.st_mode & mode)
177c80476e4SDavid E. O'Brien 	return 0;
178c80476e4SDavid E. O'Brien     else
179c80476e4SDavid E. O'Brien 	return 1;
180c80476e4SDavid E. O'Brien #endif /* !POSIX */
181c80476e4SDavid E. O'Brien }
182c80476e4SDavid E. O'Brien 
183c80476e4SDavid E. O'Brien tcsh_number_t
expr(Char *** vp)184c80476e4SDavid E. O'Brien expr(Char ***vp)
185c80476e4SDavid E. O'Brien {
186c80476e4SDavid E. O'Brien     return (exp0(vp, 0));
187c80476e4SDavid E. O'Brien }
188c80476e4SDavid E. O'Brien 
18945e5710bSMark Peek tcsh_number_t
exp0(Char *** vp,int ignore)190c80476e4SDavid E. O'Brien exp0(Char ***vp, int ignore)
191c80476e4SDavid E. O'Brien {
192c80476e4SDavid E. O'Brien     tcsh_number_t p1 = exp1(vp, ignore);
193c80476e4SDavid E. O'Brien 
194c80476e4SDavid E. O'Brien     etraci("exp0 p1", p1, vp);
19545e5710bSMark Peek     while (**vp && eq(**vp, STRor2)) {
196c80476e4SDavid E. O'Brien 	int p2;
19723338178SMark Peek 
198c80476e4SDavid E. O'Brien 	(*vp)++;
199c80476e4SDavid E. O'Brien 
200c80476e4SDavid E. O'Brien 	p2 = compat_expr ?
20123338178SMark Peek 	    exp0(vp, (ignore & TEXP_IGNORE) || p1) :
202c80476e4SDavid E. O'Brien 	    exp1(vp, (ignore & TEXP_IGNORE) || p1);
203c80476e4SDavid E. O'Brien 	if (compat_expr || !(ignore & TEXP_IGNORE))
204c80476e4SDavid E. O'Brien 	    p1 = (p1 || p2);
205c80476e4SDavid E. O'Brien 	etraci("exp0 p1", p1, vp);
206c80476e4SDavid E. O'Brien 	if (compat_expr)
207c80476e4SDavid E. O'Brien 	    break;
208c80476e4SDavid E. O'Brien     }
209c80476e4SDavid E. O'Brien     return (p1);
210c80476e4SDavid E. O'Brien }
211c80476e4SDavid E. O'Brien 
21245e5710bSMark Peek static tcsh_number_t
exp1(Char *** vp,int ignore)213c80476e4SDavid E. O'Brien exp1(Char ***vp, int ignore)
21423338178SMark Peek {
215c80476e4SDavid E. O'Brien     tcsh_number_t p1 = exp2x(vp, ignore);
216c80476e4SDavid E. O'Brien 
217c80476e4SDavid E. O'Brien     etraci("exp1 p1", p1, vp);
21823338178SMark Peek     while (**vp && eq(**vp, STRand2)) {
219c80476e4SDavid E. O'Brien 	tcsh_number_t p2;
220c80476e4SDavid E. O'Brien 
221c80476e4SDavid E. O'Brien 	(*vp)++;
222c80476e4SDavid E. O'Brien 	p2 = compat_expr ?
223c80476e4SDavid E. O'Brien 	    exp1(vp, (ignore & TEXP_IGNORE) || !p1) :
224c80476e4SDavid E. O'Brien 	    exp2x(vp, (ignore & TEXP_IGNORE) || !p1);
225c80476e4SDavid E. O'Brien 
226c80476e4SDavid E. O'Brien 	etraci("exp1 p2", p2, vp);
227c80476e4SDavid E. O'Brien 	if (compat_expr || !(ignore & TEXP_IGNORE))
228c80476e4SDavid E. O'Brien 	    p1 = (p1 && p2);
22945e5710bSMark Peek 	etraci("exp1 p1", p1, vp);
230c80476e4SDavid E. O'Brien 	if (compat_expr)
23123338178SMark Peek 	    break;
232c80476e4SDavid E. O'Brien     }
233c80476e4SDavid E. O'Brien     return (p1);
234c80476e4SDavid E. O'Brien }
23523338178SMark Peek 
236c80476e4SDavid E. O'Brien static tcsh_number_t
exp2x(Char *** vp,int ignore)237c80476e4SDavid E. O'Brien exp2x(Char ***vp, int ignore)
23823338178SMark Peek {
239c80476e4SDavid E. O'Brien     tcsh_number_t p1 = exp2a(vp, ignore);
240c80476e4SDavid E. O'Brien 
241c80476e4SDavid E. O'Brien     etraci("exp2x p1", p1, vp);
242c80476e4SDavid E. O'Brien     while (**vp && eq(**vp, STRor)) {
243c80476e4SDavid E. O'Brien 	tcsh_number_t p2;
244c80476e4SDavid E. O'Brien 
245c80476e4SDavid E. O'Brien 	(*vp)++;
24645e5710bSMark Peek 	p2 = compat_expr ?
247c80476e4SDavid E. O'Brien 	    exp2x(vp, ignore) :
24823338178SMark Peek 	    exp2a(vp, ignore);
249c80476e4SDavid E. O'Brien 	etraci("exp2x p2", p2, vp);
250c80476e4SDavid E. O'Brien 	if (compat_expr || !(ignore & TEXP_IGNORE))
251c80476e4SDavid E. O'Brien 		p1 = (p1 | p2);
25223338178SMark Peek 	etraci("exp2x p1", p1, vp);
253c80476e4SDavid E. O'Brien 	if (compat_expr)
254c80476e4SDavid E. O'Brien 	    break;
255c80476e4SDavid E. O'Brien     }
256c80476e4SDavid E. O'Brien     return (p1);
257c80476e4SDavid E. O'Brien }
258c80476e4SDavid E. O'Brien 
259c80476e4SDavid E. O'Brien static tcsh_number_t
exp2a(Char *** vp,int ignore)260c80476e4SDavid E. O'Brien exp2a(Char ***vp, int ignore)
261c80476e4SDavid E. O'Brien {
262c80476e4SDavid E. O'Brien     tcsh_number_t p1 = exp2b(vp, ignore);
26345e5710bSMark Peek 
264c80476e4SDavid E. O'Brien     etraci("exp2a p1", p1, vp);
26523338178SMark Peek     while (**vp && eq(**vp, STRcaret)) {
266c80476e4SDavid E. O'Brien 	tcsh_number_t p2;
267c80476e4SDavid E. O'Brien 
268c80476e4SDavid E. O'Brien 	(*vp)++;
26923338178SMark Peek 	p2 = compat_expr ?
270c80476e4SDavid E. O'Brien 	    exp2a(vp, ignore) :
271c80476e4SDavid E. O'Brien 	    exp2b(vp, ignore);
272c80476e4SDavid E. O'Brien 	etraci("exp2a p2", p2, vp);
273c80476e4SDavid E. O'Brien 	if (compat_expr || !(ignore & TEXP_IGNORE))
274c80476e4SDavid E. O'Brien 	    p1 = (p1 ^ p2);
275c80476e4SDavid E. O'Brien 	etraci("exp2a p1", p1, vp);
276c80476e4SDavid E. O'Brien 	if (compat_expr)
277c80476e4SDavid E. O'Brien 	    break;
278c80476e4SDavid E. O'Brien     }
279c80476e4SDavid E. O'Brien     return (p1);
28045e5710bSMark Peek }
281c80476e4SDavid E. O'Brien 
28223338178SMark Peek static tcsh_number_t
exp2b(Char *** vp,int ignore)28323338178SMark Peek exp2b(Char ***vp, int ignore)
28423338178SMark Peek {
285c80476e4SDavid E. O'Brien     tcsh_number_t p1 = exp2c(vp, ignore);
28645e5710bSMark Peek 
287c80476e4SDavid E. O'Brien     etraci("exp2b p1", p1, vp);
288c80476e4SDavid E. O'Brien     while (**vp && eq(**vp, STRand)) {
289c80476e4SDavid E. O'Brien 	tcsh_number_t p2;
290c80476e4SDavid E. O'Brien 
291c80476e4SDavid E. O'Brien 	(*vp)++;
292c80476e4SDavid E. O'Brien 	p2 = compat_expr ?
29345e5710bSMark Peek 	    exp2b(vp, ignore) :
294c80476e4SDavid E. O'Brien 	    exp2c(vp, ignore);
295c80476e4SDavid E. O'Brien 	etraci("exp2b p2", p2, vp);
296c80476e4SDavid E. O'Brien 	if (compat_expr || !(ignore & TEXP_IGNORE))
297c80476e4SDavid E. O'Brien 	    p1 = (p1 & p2);
298c80476e4SDavid E. O'Brien 	etraci("exp2b p1", p1, vp);
299c80476e4SDavid E. O'Brien 	if (compat_expr)
300c80476e4SDavid E. O'Brien 	    break;
301c80476e4SDavid E. O'Brien     }
302c80476e4SDavid E. O'Brien     return (p1);
303c80476e4SDavid E. O'Brien }
304c80476e4SDavid E. O'Brien 
305c80476e4SDavid E. O'Brien static tcsh_number_t
exp2c(Char *** vp,int ignore)306c80476e4SDavid E. O'Brien exp2c(Char ***vp, int ignore)
307c80476e4SDavid E. O'Brien {
308c80476e4SDavid E. O'Brien     Char *p1 = exp3(vp, ignore);
309c80476e4SDavid E. O'Brien     Char *p2;
310c80476e4SDavid E. O'Brien     tcsh_number_t i;
311c80476e4SDavid E. O'Brien 
312c80476e4SDavid E. O'Brien     cleanup_push(p1, xfree);
313c80476e4SDavid E. O'Brien     etracc("exp2c p1", p1, vp);
31445e5710bSMark Peek     if ((i = isa(**vp, EQOP)) != 0) {
315c80476e4SDavid E. O'Brien 	(*vp)++;
316c80476e4SDavid E. O'Brien 	if (i == EQMATCH || i == NOTEQMATCH)
317c80476e4SDavid E. O'Brien 	    ignore |= TEXP_NOGLOB;
31845e5710bSMark Peek 	p2 = exp3(vp, ignore);
319c80476e4SDavid E. O'Brien 	cleanup_push(p2, xfree);
320c80476e4SDavid E. O'Brien 	etracc("exp2c p2", p2, vp);
321c80476e4SDavid E. O'Brien 	if (!(ignore & TEXP_IGNORE))
322c80476e4SDavid E. O'Brien 	    switch ((int)i) {
32345e5710bSMark Peek 
324c80476e4SDavid E. O'Brien 	    case EQEQ:
32523338178SMark Peek 		i = eq(p1, p2);
32623338178SMark Peek 		break;
327c80476e4SDavid E. O'Brien 
328c80476e4SDavid E. O'Brien 	    case NOTEQ:
329c80476e4SDavid E. O'Brien 		i = !eq(p1, p2);
330c80476e4SDavid E. O'Brien 		break;
331c80476e4SDavid E. O'Brien 
332c80476e4SDavid E. O'Brien 	    case EQMATCH:
333c80476e4SDavid E. O'Brien 		i = Gmatch(p1, p2);
33445e5710bSMark Peek 		break;
335c80476e4SDavid E. O'Brien 
33645e5710bSMark Peek 	    case NOTEQMATCH:
337c80476e4SDavid E. O'Brien 		i = !Gmatch(p1, p2);
338c80476e4SDavid E. O'Brien 		break;
339c80476e4SDavid E. O'Brien 	    }
340c80476e4SDavid E. O'Brien 	cleanup_until(p1);
341c80476e4SDavid E. O'Brien 	return (i);
342c80476e4SDavid E. O'Brien     }
343c80476e4SDavid E. O'Brien     i = egetn(p1);
344c80476e4SDavid E. O'Brien     cleanup_until(p1);
345c80476e4SDavid E. O'Brien     return (i);
346c80476e4SDavid E. O'Brien }
347c80476e4SDavid E. O'Brien 
348c80476e4SDavid E. O'Brien static Char *
exp3(Char *** vp,int ignore)349c80476e4SDavid E. O'Brien exp3(Char ***vp, int ignore)
350c80476e4SDavid E. O'Brien {
351c80476e4SDavid E. O'Brien     Char *p1, *p2;
352c80476e4SDavid E. O'Brien     tcsh_number_t i;
353c80476e4SDavid E. O'Brien 
354c80476e4SDavid E. O'Brien     p1 = exp3a(vp, ignore);
355c80476e4SDavid E. O'Brien     etracc("exp3 p1", p1, vp);
356c80476e4SDavid E. O'Brien     while ((i = isa(**vp, RELOP)) != 0) {
35745e5710bSMark Peek 	(*vp)++;
358c80476e4SDavid E. O'Brien 	if (**vp && eq(**vp, STRequal))
359c80476e4SDavid E. O'Brien 	    i |= 1, (*vp)++;
360c80476e4SDavid E. O'Brien 	cleanup_push(p1, xfree);
361c80476e4SDavid E. O'Brien 	p2 = compat_expr ?
362c80476e4SDavid E. O'Brien 	    exp3(vp, ignore) :
363c80476e4SDavid E. O'Brien 	    exp3a(vp, ignore);
36445e5710bSMark Peek 	cleanup_push(p2, xfree);
365c80476e4SDavid E. O'Brien 	etracc("exp3 p2", p2, vp);
36645e5710bSMark Peek 	if (!(ignore & TEXP_IGNORE))
36745e5710bSMark Peek 	    switch ((int)i) {
36823338178SMark Peek 
369c80476e4SDavid E. O'Brien 	    case GTR:
370c80476e4SDavid E. O'Brien 		i = egetn(p1) > egetn(p2);
371c80476e4SDavid E. O'Brien 		break;
372c80476e4SDavid E. O'Brien 
373c80476e4SDavid E. O'Brien 	    case GTR | 1:
374c80476e4SDavid E. O'Brien 		i = egetn(p1) >= egetn(p2);
37545e5710bSMark Peek 		break;
376c80476e4SDavid E. O'Brien 
37745e5710bSMark Peek 	    case LSS:
378c80476e4SDavid E. O'Brien 		i = egetn(p1) < egetn(p2);
379c80476e4SDavid E. O'Brien 		break;
380c80476e4SDavid E. O'Brien 
381c80476e4SDavid E. O'Brien 	    case LSS | 1:
382c80476e4SDavid E. O'Brien 		i = egetn(p1) <= egetn(p2);
38345e5710bSMark Peek 		break;
384c80476e4SDavid E. O'Brien 	    }
385c80476e4SDavid E. O'Brien 	cleanup_until(p1);
386c80476e4SDavid E. O'Brien 	p1 = putn(i);
387c80476e4SDavid E. O'Brien 	etracc("exp3 p1", p1, vp);
388c80476e4SDavid E. O'Brien 	if (compat_expr)
389c80476e4SDavid E. O'Brien 	    break;
39045e5710bSMark Peek     }
391c80476e4SDavid E. O'Brien     return (p1);
39223338178SMark Peek }
39323338178SMark Peek 
394c80476e4SDavid E. O'Brien static Char *
exp3a(Char *** vp,int ignore)395c80476e4SDavid E. O'Brien exp3a(Char ***vp, int ignore)
396c80476e4SDavid E. O'Brien {
397c80476e4SDavid E. O'Brien     Char *p1, *p2;
39845e5710bSMark Peek     const Char *op;
399c80476e4SDavid E. O'Brien     tcsh_number_t i;
40045e5710bSMark Peek 
401c80476e4SDavid E. O'Brien     p1 = exp4(vp, ignore);
40245e5710bSMark Peek     etracc("exp3a p1", p1, vp);
403c80476e4SDavid E. O'Brien     op = **vp;
404c80476e4SDavid E. O'Brien     if (op && any("<>", op[0]) && op[0] == op[1]) {
405c80476e4SDavid E. O'Brien 	(*vp)++;
406c80476e4SDavid E. O'Brien 	cleanup_push(p1, xfree);
407c80476e4SDavid E. O'Brien 	p2 = compat_expr ?
408c80476e4SDavid E. O'Brien 	    exp3a(vp, ignore) :
409c80476e4SDavid E. O'Brien 	    exp4(vp, ignore);
410c80476e4SDavid E. O'Brien 	cleanup_push(p2, xfree);
411c80476e4SDavid E. O'Brien 	etracc("exp3a p2", p2, vp);
412c80476e4SDavid E. O'Brien 	if (op[0] == '<')
413c80476e4SDavid E. O'Brien 	    i = egetn(p1) << egetn(p2);
414c80476e4SDavid E. O'Brien 	else
41545e5710bSMark Peek 	    i = egetn(p1) >> egetn(p2);
416c80476e4SDavid E. O'Brien 	cleanup_until(p1);
417c80476e4SDavid E. O'Brien 	p1 = putn(i);
418c80476e4SDavid E. O'Brien 	etracc("exp3a p1", p1, vp);
419c80476e4SDavid E. O'Brien     }
420c80476e4SDavid E. O'Brien     return (p1);
421c80476e4SDavid E. O'Brien }
42245e5710bSMark Peek 
423c80476e4SDavid E. O'Brien static Char *
exp4(Char *** vp,int ignore)42423338178SMark Peek exp4(Char ***vp, int ignore)
42523338178SMark Peek {
426c80476e4SDavid E. O'Brien     Char *p1, *p2;
427c80476e4SDavid E. O'Brien     tcsh_number_t i = 0;
428c80476e4SDavid E. O'Brien 
429c80476e4SDavid E. O'Brien     p1 = exp5(vp, ignore);
430c80476e4SDavid E. O'Brien     etracc("exp4 p1", p1, vp);
43145e5710bSMark Peek     while (isa(**vp, ADDOP)) {
43245e5710bSMark Peek 	const Char *op = *(*vp)++;
433c80476e4SDavid E. O'Brien 
434c80476e4SDavid E. O'Brien 	cleanup_push(p1, xfree);
435c80476e4SDavid E. O'Brien 	p2 = compat_expr ?
436c80476e4SDavid E. O'Brien 	    exp4(vp, ignore) :
43745e5710bSMark Peek 	    exp5(vp, ignore);
438c80476e4SDavid E. O'Brien 	cleanup_push(p2, xfree);
43945e5710bSMark Peek 	etracc("exp4 p2", p2, vp);
440c80476e4SDavid E. O'Brien 	if (!(ignore & TEXP_IGNORE))
44145e5710bSMark Peek 	    switch (op[0]) {
442c80476e4SDavid E. O'Brien 
44345e5710bSMark Peek 	    case '+':
444c80476e4SDavid E. O'Brien 		i = egetn(p1) + egetn(p2);
445c80476e4SDavid E. O'Brien 		break;
446c80476e4SDavid E. O'Brien 
447c80476e4SDavid E. O'Brien 	    case '-':
448c80476e4SDavid E. O'Brien 		i = egetn(p1) - egetn(p2);
449c80476e4SDavid E. O'Brien 		break;
450c80476e4SDavid E. O'Brien 	    }
451c80476e4SDavid E. O'Brien 	cleanup_until(p1);
452c80476e4SDavid E. O'Brien 	p1 = putn(i);
453c80476e4SDavid E. O'Brien 	etracc("exp4 p1", p1, vp);
454c80476e4SDavid E. O'Brien 	if (compat_expr)
455c80476e4SDavid E. O'Brien 	    break;
456c80476e4SDavid E. O'Brien     }
457c80476e4SDavid E. O'Brien     return (p1);
458c80476e4SDavid E. O'Brien }
459c80476e4SDavid E. O'Brien 
460c80476e4SDavid E. O'Brien static Char *
exp5(Char *** vp,int ignore)461c80476e4SDavid E. O'Brien exp5(Char ***vp, int ignore)
462c80476e4SDavid E. O'Brien {
463c80476e4SDavid E. O'Brien     Char *p1, *p2;
464c80476e4SDavid E. O'Brien     tcsh_number_t i = 0;
465c80476e4SDavid E. O'Brien 
46645e5710bSMark Peek     p1 = exp6(vp, ignore);
467c80476e4SDavid E. O'Brien     etracc("exp5 p1", p1, vp);
468c80476e4SDavid E. O'Brien 
469c80476e4SDavid E. O'Brien     while (isa(**vp, MULOP)) {
470c80476e4SDavid E. O'Brien 	const Char *op = *(*vp)++;
471c80476e4SDavid E. O'Brien 	if ((ignore & TEXP_NOGLOB) != 0) {
472c80476e4SDavid E. O'Brien 	    /*
47345e5710bSMark Peek 	     * We are just trying to get the right side of
474c80476e4SDavid E. O'Brien 	     * a =~ or !~ operator
475c80476e4SDavid E. O'Brien 	     */
47623338178SMark Peek 	    xfree(p1);
477c80476e4SDavid E. O'Brien 	    return Strsave(op);
478c80476e4SDavid E. O'Brien 	}
479c80476e4SDavid E. O'Brien 
480c80476e4SDavid E. O'Brien 	cleanup_push(p1, xfree);
481c80476e4SDavid E. O'Brien 	p2 = compat_expr ?
482c80476e4SDavid E. O'Brien 	    exp5(vp, ignore) :
48345e5710bSMark Peek 	    exp6(vp, ignore);
484c80476e4SDavid E. O'Brien 	cleanup_push(p2, xfree);
485c80476e4SDavid E. O'Brien 	etracc("exp5 p2", p2, vp);
48645e5710bSMark Peek 	if (!(ignore & TEXP_IGNORE))
487c80476e4SDavid E. O'Brien 	    switch (op[0]) {
488c80476e4SDavid E. O'Brien 
489c80476e4SDavid E. O'Brien 	    case '*':
490c80476e4SDavid E. O'Brien 		i = egetn(p1) * egetn(p2);
491c80476e4SDavid E. O'Brien 		break;
49245e5710bSMark Peek 
493c80476e4SDavid E. O'Brien 	    case '/':
494c80476e4SDavid E. O'Brien 		i = egetn(p2);
49545e5710bSMark Peek 		if (i == 0)
496c80476e4SDavid E. O'Brien 		    stderror(ERR_DIV0);
497c80476e4SDavid E. O'Brien 		i = egetn(p1) / i;
498c80476e4SDavid E. O'Brien 		break;
499c80476e4SDavid E. O'Brien 
500c80476e4SDavid E. O'Brien 	    case '%':
501c80476e4SDavid E. O'Brien 		i = egetn(p2);
50245e5710bSMark Peek 		if (i == 0)
503c80476e4SDavid E. O'Brien 		    stderror(ERR_MOD0);
504c80476e4SDavid E. O'Brien 		i = egetn(p1) % i;
505c80476e4SDavid E. O'Brien 		break;
506c80476e4SDavid E. O'Brien 	    }
507c80476e4SDavid E. O'Brien 	cleanup_until(p1);
50823338178SMark Peek 	p1 = putn(i);
509c80476e4SDavid E. O'Brien 	etracc("exp5 p1", p1, vp);
510c80476e4SDavid E. O'Brien 	if (compat_expr)
511c80476e4SDavid E. O'Brien 	    break;
512c80476e4SDavid E. O'Brien     }
513c80476e4SDavid E. O'Brien     return (p1);
514c80476e4SDavid E. O'Brien }
515c80476e4SDavid E. O'Brien 
516c80476e4SDavid E. O'Brien static Char *
exp6(Char *** vp,int ignore)517c80476e4SDavid E. O'Brien exp6(Char ***vp, int ignore)
518c80476e4SDavid E. O'Brien {
519c80476e4SDavid E. O'Brien     tcsh_number_t ccode;
520c80476e4SDavid E. O'Brien     tcsh_number_t i = 0;
521c80476e4SDavid E. O'Brien     Char *cp;
522c80476e4SDavid E. O'Brien 
523c80476e4SDavid E. O'Brien     if (**vp == 0)
524c80476e4SDavid E. O'Brien 	stderror(ERR_NAME | ERR_EXPRESSION);
525c80476e4SDavid E. O'Brien     if (eq(**vp, STRbang)) {
526c80476e4SDavid E. O'Brien 	(*vp)++;
527c80476e4SDavid E. O'Brien 	cp = exp6(vp, ignore);
528c80476e4SDavid E. O'Brien 	cleanup_push(cp, xfree);
52945e5710bSMark Peek 	etracc("exp6 ! cp", cp, vp);
530c80476e4SDavid E. O'Brien 	i = egetn(cp);
531c80476e4SDavid E. O'Brien 	cleanup_until(cp);
532c80476e4SDavid E. O'Brien 	return (putn(!i));
533c80476e4SDavid E. O'Brien     }
534c80476e4SDavid E. O'Brien     if (eq(**vp, STRtilde)) {
535c80476e4SDavid E. O'Brien 	(*vp)++;
53645e5710bSMark Peek 	cp = exp6(vp, ignore);
537c80476e4SDavid E. O'Brien 	cleanup_push(cp, xfree);
538c80476e4SDavid E. O'Brien 	etracc("exp6 ~ cp", cp, vp);
539c80476e4SDavid E. O'Brien 	i = egetn(cp);
540c80476e4SDavid E. O'Brien 	cleanup_until(cp);
541c80476e4SDavid E. O'Brien 	return (putn(~i));
542c80476e4SDavid E. O'Brien     }
543c80476e4SDavid E. O'Brien     if (eq(**vp, STRLparen)) {
544c80476e4SDavid E. O'Brien 	(*vp)++;
545c80476e4SDavid E. O'Brien 	ccode = exp0(vp, ignore);
546c80476e4SDavid E. O'Brien 	etraci("exp6 () ccode", ccode, vp);
547c80476e4SDavid E. O'Brien 	if (**vp == 0 || ***vp != ')')
548c80476e4SDavid E. O'Brien 	    stderror(ERR_NAME | ERR_EXPRESSION);
549c80476e4SDavid E. O'Brien 	(*vp)++;
550c80476e4SDavid E. O'Brien 	return (putn(ccode));
551c80476e4SDavid E. O'Brien     }
552c80476e4SDavid E. O'Brien     if (eq(**vp, STRLbrace)) {
553c80476e4SDavid E. O'Brien 	Char **v;
554c80476e4SDavid E. O'Brien 	struct command faket;
555c80476e4SDavid E. O'Brien 	Char   *fakecom[2];
556c80476e4SDavid E. O'Brien 
557c80476e4SDavid E. O'Brien 	faket.t_dtyp = NODE_COMMAND;
558c80476e4SDavid E. O'Brien 	faket.t_dflg = F_BACKQ;
559c80476e4SDavid E. O'Brien 	faket.t_dcar = faket.t_dcdr = faket.t_dspr = NULL;
560c80476e4SDavid E. O'Brien 	faket.t_dcom = fakecom;
56145e5710bSMark Peek 	fakecom[0] = STRfakecom;
562c80476e4SDavid E. O'Brien 	fakecom[1] = NULL;
563c80476e4SDavid E. O'Brien 	(*vp)++;
564c80476e4SDavid E. O'Brien 	v = *vp;
565c80476e4SDavid E. O'Brien 	for (;;) {
566c80476e4SDavid E. O'Brien 	    if (!**vp)
567c80476e4SDavid E. O'Brien 		stderror(ERR_NAME | ERR_MISSING, '}');
568c80476e4SDavid E. O'Brien 	    if (eq(*(*vp)++, STRRbrace))
569c80476e4SDavid E. O'Brien 		break;
570c80476e4SDavid E. O'Brien 	}
571c80476e4SDavid E. O'Brien 	if (ignore & TEXP_IGNORE)
572c80476e4SDavid E. O'Brien 	    return (Strsave(STRNULL));
573c80476e4SDavid E. O'Brien 	psavejob();
574c80476e4SDavid E. O'Brien 	cleanup_push(&faket, psavejob_cleanup); /* faket is only a marker */
575c80476e4SDavid E. O'Brien 	if (pfork(&faket, -1) == 0) {
576c80476e4SDavid E. O'Brien 	    *--(*vp) = 0;
577c80476e4SDavid E. O'Brien 	    evalav(v);
578c80476e4SDavid E. O'Brien 	    exitstat();
579c80476e4SDavid E. O'Brien 	}
580c80476e4SDavid E. O'Brien 	pwait();
581c80476e4SDavid E. O'Brien 	cleanup_until(&faket);
582c80476e4SDavid E. O'Brien 	etraci("exp6 {} status", egetn(varval(STRstatus)), vp);
583c80476e4SDavid E. O'Brien 	return (putn(egetn(varval(STRstatus)) == 0));
58423338178SMark Peek     }
585c80476e4SDavid E. O'Brien     if (isa(**vp, ANYOP))
586c80476e4SDavid E. O'Brien 	return (Strsave(STRNULL));
587c80476e4SDavid E. O'Brien     cp = *(*vp)++;
588c80476e4SDavid E. O'Brien #ifdef convex
589c80476e4SDavid E. O'Brien # define FILETESTS "erwxfdzoplstSXLbcugkmKR"
590c80476e4SDavid E. O'Brien #else
591c80476e4SDavid E. O'Brien # define FILETESTS "erwxfdzoplstSXLbcugkmK"
592c80476e4SDavid E. O'Brien #endif /* convex */
593c80476e4SDavid E. O'Brien #define FILEVALS  "ZAMCDIUGNFPL"
594c80476e4SDavid E. O'Brien     if (*cp == '-' && (any(FILETESTS, cp[1]) || any(FILEVALS, cp[1])))
595c80476e4SDavid E. O'Brien         return(filetest(cp, vp, ignore));
596c80476e4SDavid E. O'Brien     etracc("exp6 default", cp, vp);
597c80476e4SDavid E. O'Brien     return (ignore & TEXP_NOGLOB ? Strsave(cp) : globone(cp, G_APPEND));
598c80476e4SDavid E. O'Brien }
599c80476e4SDavid E. O'Brien 
600c80476e4SDavid E. O'Brien 
601c80476e4SDavid E. O'Brien /*
602c80476e4SDavid E. O'Brien  * Extended file tests
603c80476e4SDavid E. O'Brien  * From: John Rowe <rowe@excc.exeter.ac.uk>
604c80476e4SDavid E. O'Brien  */
605c80476e4SDavid E. O'Brien Char *
filetest(Char * cp,Char *** vp,int ignore)606c80476e4SDavid E. O'Brien filetest(Char *cp, Char ***vp, int ignore)
607c80476e4SDavid E. O'Brien {
608c80476e4SDavid E. O'Brien #ifdef convex
609c80476e4SDavid E. O'Brien     struct cvxstat stb, *st = NULL;
610c80476e4SDavid E. O'Brien # define TCSH_STAT	stat64
611c80476e4SDavid E. O'Brien #else
612c80476e4SDavid E. O'Brien # define TCSH_STAT	stat
613c80476e4SDavid E. O'Brien     struct stat stb, *st = NULL;
614c80476e4SDavid E. O'Brien #endif /* convex */
615c80476e4SDavid E. O'Brien 
616c80476e4SDavid E. O'Brien #ifdef S_IFLNK
617c80476e4SDavid E. O'Brien # ifdef convex
618c80476e4SDavid E. O'Brien     struct cvxstat lstb, *lst = NULL;
619c80476e4SDavid E. O'Brien #  define TCSH_LSTAT lstat64
620c80476e4SDavid E. O'Brien # else
621c80476e4SDavid E. O'Brien #  define TCSH_LSTAT lstat
622c80476e4SDavid E. O'Brien     struct stat lstb, *lst = NULL;
623c80476e4SDavid E. O'Brien # endif /* convex */
624c80476e4SDavid E. O'Brien     char *filnam;
625c80476e4SDavid E. O'Brien #endif /* S_IFLNK */
626c80476e4SDavid E. O'Brien 
627c80476e4SDavid E. O'Brien     tcsh_number_t i = 0;
628c80476e4SDavid E. O'Brien     unsigned pmask = 0xffff;
629c80476e4SDavid E. O'Brien     int altout = 0;
630c80476e4SDavid E. O'Brien     Char *ft = cp, *dp, *ep, *strdev, *strino, *strF, *str, valtest = '\0',
631c80476e4SDavid E. O'Brien     *errval = STR0;
632c80476e4SDavid E. O'Brien     char *string, string0[22 + MB_LEN_MAX + 1];	/* space for 64 bit octal */
633c80476e4SDavid E. O'Brien     time_t footime;
634c80476e4SDavid E. O'Brien     struct passwd *pw;
635c80476e4SDavid E. O'Brien     struct group *gr;
63645e5710bSMark Peek 
637c80476e4SDavid E. O'Brien     while (any(FILETESTS, *++ft))
638c80476e4SDavid E. O'Brien 	continue;
639c80476e4SDavid E. O'Brien 
640c80476e4SDavid E. O'Brien     if (!*ft && *(ft - 1) == 'L')
641c80476e4SDavid E. O'Brien 	--ft;
642c80476e4SDavid E. O'Brien 
643c80476e4SDavid E. O'Brien     if (any(FILEVALS, *ft)) {
644c80476e4SDavid E. O'Brien 	valtest = *ft++;
645c80476e4SDavid E. O'Brien 	/*
646c80476e4SDavid E. O'Brien 	 * Value tests return '-1' on failure as 0 is
647c80476e4SDavid E. O'Brien 	 * a legitimate value for many of them.
648c80476e4SDavid E. O'Brien 	 * 'F' returns ':' for compatibility.
649c80476e4SDavid E. O'Brien 	 */
650c80476e4SDavid E. O'Brien 	errval = valtest == 'F' ? STRcolon : STRminus1;
651c80476e4SDavid E. O'Brien 
652c80476e4SDavid E. O'Brien 	if (valtest == 'P' && *ft >= '0' && *ft <= '7') {
653c80476e4SDavid E. O'Brien 	    pmask = (char) *ft - '0';
654c80476e4SDavid E. O'Brien 	    while ( *++ft >= '0' && *ft <= '7' )
655c80476e4SDavid E. O'Brien 		pmask = 8 * pmask + ((char) *ft - '0');
656c80476e4SDavid E. O'Brien 	}
657c80476e4SDavid E. O'Brien 	if (Strcmp(ft, STRcolon) == 0 && any("AMCUGP", valtest)) {
658c80476e4SDavid E. O'Brien 	    altout = 1;
659c80476e4SDavid E. O'Brien 	    ++ft;
660c80476e4SDavid E. O'Brien 	}
661c80476e4SDavid E. O'Brien     }
662c80476e4SDavid E. O'Brien 
663c80476e4SDavid E. O'Brien     if (*ft || ft == cp + 1)
664c80476e4SDavid E. O'Brien 	stderror(ERR_NAME | ERR_FILEINQ);
665c80476e4SDavid E. O'Brien 
666c80476e4SDavid E. O'Brien     /*
667c80476e4SDavid E. O'Brien      * Detect missing file names by checking for operator in the file name
668c80476e4SDavid E. O'Brien      * position.  However, if an operator name appears there, we must make
669c80476e4SDavid E. O'Brien      * sure that there's no file by that name (e.g., "/") before announcing
670c80476e4SDavid E. O'Brien      * an error.  Even this check isn't quite right, since it doesn't take
671c80476e4SDavid E. O'Brien      * globbing into account.
672c80476e4SDavid E. O'Brien      */
67345e5710bSMark Peek 
674c80476e4SDavid E. O'Brien     if (isa(**vp, ANYOP) && TCSH_STAT(short2str(**vp), &stb))
675c80476e4SDavid E. O'Brien 	stderror(ERR_NAME | ERR_FILENAME);
676c80476e4SDavid E. O'Brien 
677c80476e4SDavid E. O'Brien     dp = *(*vp)++;
678c80476e4SDavid E. O'Brien     if (ignore & TEXP_IGNORE)
679c80476e4SDavid E. O'Brien 	return (Strsave(STRNULL));
680c80476e4SDavid E. O'Brien     ep = globone(dp, G_APPEND);
681c80476e4SDavid E. O'Brien     cleanup_push(ep, xfree);
682c80476e4SDavid E. O'Brien     ft = &cp[1];
683c80476e4SDavid E. O'Brien     do
684c80476e4SDavid E. O'Brien 	switch (*ft) {
685c80476e4SDavid E. O'Brien 
686c80476e4SDavid E. O'Brien 	case 'r':
687c80476e4SDavid E. O'Brien 	    i = !sh_access(ep, R_OK);
68845e5710bSMark Peek 	    break;
689c80476e4SDavid E. O'Brien 
690c80476e4SDavid E. O'Brien 	case 'w':
691c80476e4SDavid E. O'Brien 	    i = !sh_access(ep, W_OK);
692c80476e4SDavid E. O'Brien 	    break;
693c80476e4SDavid E. O'Brien 
694c80476e4SDavid E. O'Brien 	case 'x':
695c80476e4SDavid E. O'Brien 	    i = !sh_access(ep, X_OK);
696c80476e4SDavid E. O'Brien 	    break;
697c80476e4SDavid E. O'Brien 
698c80476e4SDavid E. O'Brien 	case 'X':	/* tcsh extension, name is an executable in the path
699c80476e4SDavid E. O'Brien 			 * or a tcsh builtin command
700c80476e4SDavid E. O'Brien 			 */
701c80476e4SDavid E. O'Brien 	    i = find_cmd(ep, 0);
702c80476e4SDavid E. O'Brien 	    break;
703c80476e4SDavid E. O'Brien 
704c80476e4SDavid E. O'Brien 	case 't':	/* SGI extension, true when file is a tty */
705c80476e4SDavid E. O'Brien 	    i = isatty(atoi(short2str(ep)));
706c80476e4SDavid E. O'Brien 	    break;
707c80476e4SDavid E. O'Brien 
708c80476e4SDavid E. O'Brien 	default:
709c80476e4SDavid E. O'Brien 
710c80476e4SDavid E. O'Brien #ifdef S_IFLNK
711c80476e4SDavid E. O'Brien 	    if (tolower(*ft) == 'l') {
712c80476e4SDavid E. O'Brien 		/*
713c80476e4SDavid E. O'Brien 		 * avoid convex compiler bug.
714c80476e4SDavid E. O'Brien 		 */
715c80476e4SDavid E. O'Brien 		if (!lst) {
716c80476e4SDavid E. O'Brien 		    lst = &lstb;
717c80476e4SDavid E. O'Brien 		    if (TCSH_LSTAT(short2str(ep), lst) == -1) {
718c80476e4SDavid E. O'Brien 			cleanup_until(ep);
719c80476e4SDavid E. O'Brien 			return (Strsave(errval));
720c80476e4SDavid E. O'Brien 		    }
721c80476e4SDavid E. O'Brien 		}
722c80476e4SDavid E. O'Brien 		if (*ft == 'L')
723c80476e4SDavid E. O'Brien 		    st = lst;
724c80476e4SDavid E. O'Brien 	    }
725c80476e4SDavid E. O'Brien 	    else
726c80476e4SDavid E. O'Brien #endif /* S_IFLNK */
727c80476e4SDavid E. O'Brien 		/*
728c80476e4SDavid E. O'Brien 		 * avoid convex compiler bug.
729c80476e4SDavid E. O'Brien 		 */
730c80476e4SDavid E. O'Brien 		if (!st) {
731c80476e4SDavid E. O'Brien 		    st = &stb;
732c80476e4SDavid E. O'Brien 		    if (TCSH_STAT(short2str(ep), st) == -1) {
733c80476e4SDavid E. O'Brien 			cleanup_until(ep);
734c80476e4SDavid E. O'Brien 			return (Strsave(errval));
735c80476e4SDavid E. O'Brien 		    }
736c80476e4SDavid E. O'Brien 		}
737c80476e4SDavid E. O'Brien 
738c80476e4SDavid E. O'Brien 	    switch (*ft) {
739c80476e4SDavid E. O'Brien 
740c80476e4SDavid E. O'Brien 	    case 'f':
741c80476e4SDavid E. O'Brien #ifdef S_ISREG
742c80476e4SDavid E. O'Brien 		i = S_ISREG(st->st_mode);
743c80476e4SDavid E. O'Brien #else /* !S_ISREG */
744c80476e4SDavid E. O'Brien 		i = 0;
745c80476e4SDavid E. O'Brien #endif /* S_ISREG */
746c80476e4SDavid E. O'Brien 		break;
747c80476e4SDavid E. O'Brien 
748c80476e4SDavid E. O'Brien 	    case 'd':
749c80476e4SDavid E. O'Brien #ifdef S_ISDIR
750c80476e4SDavid E. O'Brien 		i = S_ISDIR(st->st_mode);
751c80476e4SDavid E. O'Brien #else /* !S_ISDIR */
752c80476e4SDavid E. O'Brien 		i = 0;
753c80476e4SDavid E. O'Brien #endif /* S_ISDIR */
754c80476e4SDavid E. O'Brien 		break;
755c80476e4SDavid E. O'Brien 
756c80476e4SDavid E. O'Brien 	    case 'p':
757c80476e4SDavid E. O'Brien #ifdef S_ISFIFO
758c80476e4SDavid E. O'Brien 		i = S_ISFIFO(st->st_mode);
759c80476e4SDavid E. O'Brien #else /* !S_ISFIFO */
760c80476e4SDavid E. O'Brien 		i = 0;
761c80476e4SDavid E. O'Brien #endif /* S_ISFIFO */
762c80476e4SDavid E. O'Brien 		break;
763c80476e4SDavid E. O'Brien 
764c80476e4SDavid E. O'Brien 	    case 'm' :
765c80476e4SDavid E. O'Brien #ifdef S_ISOFL
766c80476e4SDavid E. O'Brien 	      i = S_ISOFL(st->st_dm_mode);
767c80476e4SDavid E. O'Brien #else /* !S_ISOFL */
768c80476e4SDavid E. O'Brien 	      i = 0;
769c80476e4SDavid E. O'Brien #endif /* S_ISOFL */
770c80476e4SDavid E. O'Brien 	      break ;
771c80476e4SDavid E. O'Brien 
772c80476e4SDavid E. O'Brien 	    case 'K' :
773c80476e4SDavid E. O'Brien #ifdef S_ISOFL
774c80476e4SDavid E. O'Brien 	      i = stb.st_dm_key;
775c80476e4SDavid E. O'Brien #else /* !S_ISOFL */
776c80476e4SDavid E. O'Brien 	      i = 0;
777c80476e4SDavid E. O'Brien #endif /* S_ISOFL */
778c80476e4SDavid E. O'Brien 	      break ;
779c80476e4SDavid E. O'Brien 
780c80476e4SDavid E. O'Brien 
781c80476e4SDavid E. O'Brien 	    case 'l':
782c80476e4SDavid E. O'Brien #ifdef S_ISLNK
783c80476e4SDavid E. O'Brien 		i = S_ISLNK(lst->st_mode);
784c80476e4SDavid E. O'Brien #else /* !S_ISLNK */
785c80476e4SDavid E. O'Brien 		i = 0;
786c80476e4SDavid E. O'Brien #endif /* S_ISLNK */
787c80476e4SDavid E. O'Brien 		break;
788c80476e4SDavid E. O'Brien 
789c80476e4SDavid E. O'Brien 	    case 'S':
790c80476e4SDavid E. O'Brien # ifdef S_ISSOCK
791c80476e4SDavid E. O'Brien 		i = S_ISSOCK(st->st_mode);
792c80476e4SDavid E. O'Brien # else /* !S_ISSOCK */
793c80476e4SDavid E. O'Brien 		i = 0;
794c80476e4SDavid E. O'Brien # endif /* S_ISSOCK */
795c80476e4SDavid E. O'Brien 		break;
796c80476e4SDavid E. O'Brien 
797c80476e4SDavid E. O'Brien 	    case 'b':
798c80476e4SDavid E. O'Brien #ifdef S_ISBLK
799c80476e4SDavid E. O'Brien 		i = S_ISBLK(st->st_mode);
800c80476e4SDavid E. O'Brien #else /* !S_ISBLK */
801c80476e4SDavid E. O'Brien 		i = 0;
802c80476e4SDavid E. O'Brien #endif /* S_ISBLK */
803c80476e4SDavid E. O'Brien 		break;
804c80476e4SDavid E. O'Brien 
805c80476e4SDavid E. O'Brien 	    case 'c':
806c80476e4SDavid E. O'Brien #ifdef S_ISCHR
807c80476e4SDavid E. O'Brien 		i = S_ISCHR(st->st_mode);
808c80476e4SDavid E. O'Brien #else /* !S_ISCHR */
809c80476e4SDavid E. O'Brien 		i = 0;
810c80476e4SDavid E. O'Brien #endif /* S_ISCHR */
811c80476e4SDavid E. O'Brien 		break;
812c80476e4SDavid E. O'Brien 
813c80476e4SDavid E. O'Brien 	    case 'u':
814c80476e4SDavid E. O'Brien 		i = (S_ISUID & st->st_mode) != 0;
815c80476e4SDavid E. O'Brien 		break;
816c80476e4SDavid E. O'Brien 
81745e5710bSMark Peek 	    case 'g':
81845e5710bSMark Peek 		i = (S_ISGID & st->st_mode) != 0;
819c80476e4SDavid E. O'Brien 		break;
82045e5710bSMark Peek 
82145e5710bSMark Peek 	    case 'k':
82245e5710bSMark Peek 		i = (S_ISVTX & st->st_mode) != 0;
823c80476e4SDavid E. O'Brien 		break;
824c80476e4SDavid E. O'Brien 
825c80476e4SDavid E. O'Brien 	    case 'z':
826c80476e4SDavid E. O'Brien 		i = st->st_size == 0;
827c80476e4SDavid E. O'Brien 		break;
828c80476e4SDavid E. O'Brien 
829c80476e4SDavid E. O'Brien #ifdef convex
830c80476e4SDavid E. O'Brien 	    case 'R':
831c80476e4SDavid E. O'Brien 		i = (stb.st_dmonflags & IMIGRATED) == IMIGRATED;
83245e5710bSMark Peek 		break;
83345e5710bSMark Peek #endif /* convex */
83445e5710bSMark Peek 
83545e5710bSMark Peek 	    case 's':
836c80476e4SDavid E. O'Brien 		i = stb.st_size != 0;
837c80476e4SDavid E. O'Brien 		break;
838c80476e4SDavid E. O'Brien 
839c80476e4SDavid E. O'Brien 	    case 'e':
840c80476e4SDavid E. O'Brien 		i = 1;
841c80476e4SDavid E. O'Brien 		break;
842c80476e4SDavid E. O'Brien 
843c80476e4SDavid E. O'Brien 	    case 'o':
844c80476e4SDavid E. O'Brien 		i = st->st_uid == uid;
845c80476e4SDavid E. O'Brien 		break;
846c80476e4SDavid E. O'Brien 
847c80476e4SDavid E. O'Brien 		/*
848c80476e4SDavid E. O'Brien 		 * Value operators are a tcsh extension.
849c80476e4SDavid E. O'Brien 		 */
850c80476e4SDavid E. O'Brien 
851c80476e4SDavid E. O'Brien 	    case 'D':
852c80476e4SDavid E. O'Brien 		i = (tcsh_number_t) st->st_dev;
853c80476e4SDavid E. O'Brien 		break;
854c80476e4SDavid E. O'Brien 
85545e5710bSMark Peek 	    case 'I':
856c80476e4SDavid E. O'Brien 		i = (tcsh_number_t) st->st_ino;
857c80476e4SDavid E. O'Brien 		break;
858c80476e4SDavid E. O'Brien 
85945e5710bSMark Peek 	    case 'F':
86045e5710bSMark Peek 		strdev = putn( (int) st->st_dev);
861c80476e4SDavid E. O'Brien 		strino = putn( (int) st->st_ino);
862c80476e4SDavid E. O'Brien 		strF = xmalloc((2 + Strlen(strdev) + Strlen(strino))
863c80476e4SDavid E. O'Brien 			       * sizeof(Char));
864c80476e4SDavid E. O'Brien 		(void) Strcat(Strcat(Strcpy(strF, strdev), STRcolon), strino);
865c80476e4SDavid E. O'Brien 		xfree(strdev);
866c80476e4SDavid E. O'Brien 		xfree(strino);
86745e5710bSMark Peek 		cleanup_until(ep);
86845e5710bSMark Peek 		return(strF);
869c80476e4SDavid E. O'Brien 
870c80476e4SDavid E. O'Brien 	    case 'L':
871c80476e4SDavid E. O'Brien 		if ( *(ft + 1) ) {
872c80476e4SDavid E. O'Brien 		    i = 1;
873c80476e4SDavid E. O'Brien 		    break;
874c80476e4SDavid E. O'Brien 		}
875c80476e4SDavid E. O'Brien #ifdef S_ISLNK
876c80476e4SDavid E. O'Brien 		filnam = short2str(ep);
877c80476e4SDavid E. O'Brien 		string = areadlink(filnam);
878c80476e4SDavid E. O'Brien 		strF = string == NULL ? errval : str2short(string);
879c80476e4SDavid E. O'Brien 		xfree(string);
880c80476e4SDavid E. O'Brien 		cleanup_until(ep);
881c80476e4SDavid E. O'Brien 		return(Strsave(strF));
882c80476e4SDavid E. O'Brien 
883c80476e4SDavid E. O'Brien #else /* !S_ISLNK */
884c80476e4SDavid E. O'Brien 		i = 0;
88545e5710bSMark Peek 		break;
886c80476e4SDavid E. O'Brien #endif /* S_ISLNK */
887c80476e4SDavid E. O'Brien 
888c80476e4SDavid E. O'Brien 
889c80476e4SDavid E. O'Brien 	    case 'N':
890c80476e4SDavid E. O'Brien 		i = (tcsh_number_t) st->st_nlink;
891c80476e4SDavid E. O'Brien 		break;
892c80476e4SDavid E. O'Brien 
893c80476e4SDavid E. O'Brien 	    case 'P':
894c80476e4SDavid E. O'Brien 		string = string0 + 1;
89545e5710bSMark Peek 		(void) xsnprintf(string, sizeof(string0) - 1, "%o",
896c80476e4SDavid E. O'Brien 		    pmask & (unsigned int)
897c80476e4SDavid E. O'Brien 		    ((S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID) & st->st_mode));
898c80476e4SDavid E. O'Brien 		if (altout && *string != '0')
899c80476e4SDavid E. O'Brien 		    *--string = '0';
900c80476e4SDavid E. O'Brien 		cleanup_until(ep);
90145e5710bSMark Peek 		return(Strsave(str2short(string)));
902c80476e4SDavid E. O'Brien 
903c80476e4SDavid E. O'Brien 	    case 'U':
90423338178SMark Peek 		if (altout && (pw = xgetpwuid(st->st_uid))) {
905c80476e4SDavid E. O'Brien 		    cleanup_until(ep);
90623338178SMark Peek 		    return(Strsave(str2short(pw->pw_name)));
907c80476e4SDavid E. O'Brien 		}
90845e5710bSMark Peek 		i = (tcsh_number_t) st->st_uid;
909c80476e4SDavid E. O'Brien 		break;
910c80476e4SDavid E. O'Brien 
911c80476e4SDavid E. O'Brien 	    case 'G':
91245e5710bSMark Peek 		if (altout && (gr = xgetgrgid(st->st_gid))) {
913c80476e4SDavid E. O'Brien 		    cleanup_until(ep);
914c80476e4SDavid E. O'Brien 		    return(Strsave(str2short(gr->gr_name)));
915c80476e4SDavid E. O'Brien 		}
916c80476e4SDavid E. O'Brien 		i = (tcsh_number_t) st->st_gid;
917c80476e4SDavid E. O'Brien 		break;
918c80476e4SDavid E. O'Brien 
919c80476e4SDavid E. O'Brien 	    case 'Z':
920c80476e4SDavid E. O'Brien 		i = (tcsh_number_t) st->st_size;
92145e5710bSMark Peek 		break;
922c80476e4SDavid E. O'Brien 
923c80476e4SDavid E. O'Brien 	    case 'A': case 'M': case 'C':
92445e5710bSMark Peek 		footime = *ft == 'A' ? st->st_atime :
925c80476e4SDavid E. O'Brien 		    *ft == 'M' ? st->st_mtime : st->st_ctime;
926c80476e4SDavid E. O'Brien 		if (altout) {
92729301572SMark Peek 		    strF = str2short(ctime(&footime));
92845e5710bSMark Peek 		    if ((str = Strchr(strF, '\n')) != NULL)
929c80476e4SDavid E. O'Brien 			*str = (Char) '\0';
930c80476e4SDavid E. O'Brien 		    cleanup_until(ep);
931c80476e4SDavid E. O'Brien 		    return(Strsave(strF));
93245e5710bSMark Peek 		}
933c80476e4SDavid E. O'Brien 		i = (tcsh_number_t) footime;
934c80476e4SDavid E. O'Brien 		break;
935c80476e4SDavid E. O'Brien 
936c80476e4SDavid E. O'Brien 	    }
937c80476e4SDavid E. O'Brien 	}
938c80476e4SDavid E. O'Brien     while (*++ft && i);
939c80476e4SDavid E. O'Brien     etraci("exp6 -? i", i, vp);
940c80476e4SDavid E. O'Brien     cleanup_until(ep);
941c80476e4SDavid E. O'Brien     return (putn(i));
942c80476e4SDavid E. O'Brien }
943c80476e4SDavid E. O'Brien 
944c80476e4SDavid E. O'Brien 
945c80476e4SDavid E. O'Brien static void
evalav(Char ** v)946c80476e4SDavid E. O'Brien evalav(Char **v)
947c80476e4SDavid E. O'Brien {
948c80476e4SDavid E. O'Brien     struct wordent paraml1;
949c80476e4SDavid E. O'Brien     struct wordent *hp = &paraml1;
950c80476e4SDavid E. O'Brien     struct command *t;
951c80476e4SDavid E. O'Brien     struct wordent *wdp = hp;
952c80476e4SDavid E. O'Brien 
953c80476e4SDavid E. O'Brien     setcopy(STRstatus, STR0, VAR_READWRITE);
954c80476e4SDavid E. O'Brien     initlex(hp);
955c80476e4SDavid E. O'Brien     while (*v) {
956c80476e4SDavid E. O'Brien 	struct wordent *new = xcalloc(1, sizeof *wdp);
957c80476e4SDavid E. O'Brien 
958c80476e4SDavid E. O'Brien 	new->prev = wdp;
959c80476e4SDavid E. O'Brien 	new->next = hp;
960c80476e4SDavid E. O'Brien 	wdp->next = new;
961c80476e4SDavid E. O'Brien 	wdp = new;
962c80476e4SDavid E. O'Brien 	wdp->word = Strsave(*v++);
963c80476e4SDavid E. O'Brien     }
964c80476e4SDavid E. O'Brien     hp->prev = wdp;
965c80476e4SDavid E. O'Brien     cleanup_push(&paraml1, lex_cleanup);
966c80476e4SDavid E. O'Brien     alias(&paraml1);
967c80476e4SDavid E. O'Brien     t = syntax(paraml1.next, &paraml1, 0);
968c80476e4SDavid E. O'Brien     cleanup_push(t, syntax_cleanup);
969c80476e4SDavid E. O'Brien     if (seterr)
970c80476e4SDavid E. O'Brien 	stderror(ERR_OLD);
971c80476e4SDavid E. O'Brien     execute(t, -1, NULL, NULL, TRUE);
972c80476e4SDavid E. O'Brien     cleanup_until(&paraml1);
973c80476e4SDavid E. O'Brien }
974c80476e4SDavid E. O'Brien 
975c80476e4SDavid E. O'Brien static int
isa(Char * cp,int what)976c80476e4SDavid E. O'Brien isa(Char *cp, int what)
977c80476e4SDavid E. O'Brien {
978c80476e4SDavid E. O'Brien     if (cp == 0)
979c80476e4SDavid E. O'Brien 	return ((what & RESTOP) != 0);
980c80476e4SDavid E. O'Brien     if (*cp == '\0')
98145e5710bSMark Peek     	return 0;
982c80476e4SDavid E. O'Brien     if (cp[1] == 0) {
983c80476e4SDavid E. O'Brien 	if (what & ADDOP && (*cp == '+' || *cp == '-'))
984c80476e4SDavid E. O'Brien 	    return (1);
985c80476e4SDavid E. O'Brien 	if (what & MULOP && (*cp == '*' || *cp == '/' || *cp == '%'))
986c80476e4SDavid E. O'Brien 	    return (1);
987c80476e4SDavid E. O'Brien 	if (what & RESTOP && (*cp == '(' || *cp == ')' || *cp == '!' ||
988c80476e4SDavid E. O'Brien 			      *cp == '~' || *cp == '^' || *cp == '"'))
989c80476e4SDavid E. O'Brien 	    return (1);
990c80476e4SDavid E. O'Brien     }
991c80476e4SDavid E. O'Brien     else if (cp[2] == 0) {
99245e5710bSMark Peek 	if (what & RESTOP) {
993c80476e4SDavid E. O'Brien 	    if (cp[0] == '|' && cp[1] == '&')
994c80476e4SDavid E. O'Brien 		return (1);
995c80476e4SDavid E. O'Brien 	    if (cp[0] == '<' && cp[1] == '<')
996c80476e4SDavid E. O'Brien 		return (1);
997c80476e4SDavid E. O'Brien 	    if (cp[0] == '>' && cp[1] == '>')
998c80476e4SDavid E. O'Brien 		return (1);
99945e5710bSMark Peek 	}
1000c80476e4SDavid E. O'Brien 	if (what & EQOP) {
1001c80476e4SDavid E. O'Brien 	    if (cp[0] == '=') {
1002c80476e4SDavid E. O'Brien 		if (cp[1] == '=')
1003c80476e4SDavid E. O'Brien 		    return (EQEQ);
1004c80476e4SDavid E. O'Brien 		if (cp[1] == '~')
1005c80476e4SDavid E. O'Brien 		    return (EQMATCH);
1006 	    }
1007 	    else if (cp[0] == '!') {
1008 		if (cp[1] == '=')
1009 		    return (NOTEQ);
1010 		if (cp[1] == '~')
1011 		    return (NOTEQMATCH);
1012 	    }
1013 	}
1014     }
1015     if (what & RELOP) {
1016 	if (*cp == '<')
1017 	    return (LSS);
1018 	if (*cp == '>')
1019 	    return (GTR);
1020     }
1021     return (0);
1022 }
1023 
1024 static tcsh_number_t
egetn(const Char * cp)1025 egetn(const Char *cp)
1026 {
1027     if (*cp && *cp != '-' && !Isdigit(*cp))
1028 	stderror(ERR_NAME | ERR_EXPRESSION);
1029     return (getn(cp));
1030 }
1031 
1032 /* Phew! */
1033 
1034 #ifdef EDEBUG
1035 static void
etraci(const char * str,tcsh_number_t i,Char *** vp)1036 etraci(const char *str, tcsh_number_t i, Char ***vp)
1037 {
1038 #ifdef HAVE_LONG_LONG
1039     xprintf("%s=%lld\t", str, i);
1040 #else
1041     xprintf("%s=%ld\t", str, i);
1042 #endif
1043     blkpr(*vp);
1044     xputchar('\n');
1045 }
1046 static void
etracc(const char * str,const Char * cp,Char *** vp)1047 etracc(const char *str, const Char *cp, Char ***vp)
1048 {
1049     xprintf("%s=%S\t", str, cp);
1050     blkpr(*vp);
1051     xputchar('\n');
1052 }
1053 #endif /* EDEBUG */
1054