IMPORT openssh-9.8p1
[dragonfly.git] / contrib / tcsh-6 / sh.exp.c
blobf291a59d35267e5d2cd4071d14b05bdff0bfdbfb
1 /*
2 * sh.exp.c: Expression evaluations
3 */
4 /*-
5 * Copyright (c) 1980, 1991 The Regents of the University of California.
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
32 #include "sh.h"
33 #include "tw.h"
36 * C shell
39 #define ADDOP 1
40 #define MULOP 2
41 #define EQOP 4
42 #define RELOP 8
43 #define RESTOP 16
44 #define ANYOP 31
46 #define EQEQ 1
47 #define GTR 2
48 #define LSS 4
49 #define NOTEQ 6
50 #define EQMATCH 7
51 #define NOTEQMATCH 8
53 static int sh_access (const Char *, int);
54 static tcsh_number_t exp1 (Char ***, int);
55 static tcsh_number_t exp2x (Char ***, int);
56 static tcsh_number_t exp2a (Char ***, int);
57 static tcsh_number_t exp2b (Char ***, int);
58 static tcsh_number_t exp2c (Char ***, int);
59 static Char *exp3 (Char ***, int);
60 static Char *exp3a (Char ***, int);
61 static Char *exp4 (Char ***, int);
62 static Char *exp5 (Char ***, int);
63 static Char *exp6 (Char ***, int);
64 static void evalav (Char **);
65 static int isa (Char *, int);
66 static tcsh_number_t egetn (const Char *);
68 #ifdef EDEBUG
69 static void etracc (const char *, const Char *, Char ***);
70 static void etraci (const char *, tcsh_number_t, Char ***);
71 #else /* !EDEBUG */
72 #define etracc(A, B, C) ((void)0)
73 #define etraci(A, B, C) ((void)0)
74 #endif /* !EDEBUG */
77 * shell access function according to POSIX and non POSIX
78 * From Beto Appleton (beto@aixwiz.aix.ibm.com)
80 static int
81 sh_access(const Char *fname, int mode)
83 #if defined(POSIX) && !defined(USE_ACCESS)
84 struct stat statb;
85 #endif /* POSIX */
86 char *name = short2str(fname);
88 if (*name == '\0')
89 return 1;
91 #if !defined(POSIX) || defined(USE_ACCESS)
92 return access(name, mode);
93 #else /* POSIX */
96 * POSIX 1003.2-d11.2
97 * -r file True if file exists and is readable.
98 * -w file True if file exists and is writable.
99 * True shall indicate only that the write flag is on.
100 * The file shall not be writable on a read-only file
101 * system even if this test indicates true.
102 * -x file True if file exists and is executable.
103 * True shall indicate only that the execute flag is on.
104 * If file is a directory, true indicates that the file
105 * can be searched.
107 if (mode != W_OK && mode != X_OK)
108 return access(name, mode);
110 if (stat(name, &statb) == -1)
111 return 1;
113 if (access(name, mode) == 0) {
114 #ifdef S_ISDIR
115 if (S_ISDIR(statb.st_mode) && mode == X_OK)
116 return 0;
117 #endif /* S_ISDIR */
119 /* root needs permission for someone */
120 switch (mode) {
121 case W_OK:
122 mode = S_IWUSR | S_IWGRP | S_IWOTH;
123 break;
124 case X_OK:
125 mode = S_IXUSR | S_IXGRP | S_IXOTH;
126 break;
127 default:
128 abort();
129 break;
134 else if (euid == statb.st_uid)
135 mode <<= 6;
137 else if (egid == statb.st_gid)
138 mode <<= 3;
140 # ifdef NGROUPS_MAX
141 else {
142 /* you can be in several groups */
143 long n;
144 GETGROUPS_T *groups;
147 * Try these things to find a positive maximum groups value:
148 * 1) sysconf(_SC_NGROUPS_MAX)
149 * 2) NGROUPS_MAX
150 * 3) getgroups(0, unused)
151 * Then allocate and scan the groups array if one of these worked.
153 # if defined (HAVE_SYSCONF) && defined (_SC_NGROUPS_MAX)
154 if ((n = sysconf(_SC_NGROUPS_MAX)) == -1)
155 # endif /* _SC_NGROUPS_MAX */
156 n = NGROUPS_MAX;
157 if (n <= 0)
158 n = getgroups(0, (GETGROUPS_T *) NULL);
160 if (n > 0) {
161 groups = xmalloc(n * sizeof(*groups));
162 n = getgroups((int) n, groups);
163 while (--n >= 0)
164 if (groups[n] == statb.st_gid) {
165 mode <<= 3;
166 break;
168 xfree(groups);
171 # endif /* NGROUPS_MAX */
173 if (statb.st_mode & mode)
174 return 0;
175 else
176 return 1;
177 #endif /* !POSIX */
180 tcsh_number_t
181 expr(Char ***vp)
183 return (exp0(vp, 0));
186 tcsh_number_t
187 exp0(Char ***vp, int ignore)
189 tcsh_number_t p1 = exp1(vp, ignore);
191 etraci("exp0 p1", p1, vp);
192 while (**vp && eq(**vp, STRor2)) {
193 int p2;
195 (*vp)++;
197 p2 = compat_expr ?
198 exp0(vp, (ignore & TEXP_IGNORE) || p1) :
199 exp1(vp, (ignore & TEXP_IGNORE) || p1);
200 if (compat_expr || !(ignore & TEXP_IGNORE))
201 p1 = (p1 || p2);
202 etraci("exp0 p1", p1, vp);
203 if (compat_expr)
204 break;
206 return (p1);
209 static tcsh_number_t
210 exp1(Char ***vp, int ignore)
212 tcsh_number_t p1 = exp2x(vp, ignore);
214 etraci("exp1 p1", p1, vp);
215 while (**vp && eq(**vp, STRand2)) {
216 tcsh_number_t p2;
218 (*vp)++;
219 p2 = compat_expr ?
220 exp1(vp, (ignore & TEXP_IGNORE) || !p1) :
221 exp2x(vp, (ignore & TEXP_IGNORE) || !p1);
223 etraci("exp1 p2", p2, vp);
224 if (compat_expr || !(ignore & TEXP_IGNORE))
225 p1 = (p1 && p2);
226 etraci("exp1 p1", p1, vp);
227 if (compat_expr)
228 break;
230 return (p1);
233 static tcsh_number_t
234 exp2x(Char ***vp, int ignore)
236 tcsh_number_t p1 = exp2a(vp, ignore);
238 etraci("exp2x p1", p1, vp);
239 while (**vp && eq(**vp, STRor)) {
240 tcsh_number_t p2;
242 (*vp)++;
243 p2 = compat_expr ?
244 exp2x(vp, ignore) :
245 exp2a(vp, ignore);
246 etraci("exp2x p2", p2, vp);
247 if (compat_expr || !(ignore & TEXP_IGNORE))
248 p1 = (p1 | p2);
249 etraci("exp2x p1", p1, vp);
250 if (compat_expr)
251 break;
253 return (p1);
256 static tcsh_number_t
257 exp2a(Char ***vp, int ignore)
259 tcsh_number_t p1 = exp2b(vp, ignore);
261 etraci("exp2a p1", p1, vp);
262 while (**vp && eq(**vp, STRcaret)) {
263 tcsh_number_t p2;
265 (*vp)++;
266 p2 = compat_expr ?
267 exp2a(vp, ignore) :
268 exp2b(vp, ignore);
269 etraci("exp2a p2", p2, vp);
270 if (compat_expr || !(ignore & TEXP_IGNORE))
271 p1 = (p1 ^ p2);
272 etraci("exp2a p1", p1, vp);
273 if (compat_expr)
274 break;
276 return (p1);
279 static tcsh_number_t
280 exp2b(Char ***vp, int ignore)
282 tcsh_number_t p1 = exp2c(vp, ignore);
284 etraci("exp2b p1", p1, vp);
285 while (**vp && eq(**vp, STRand)) {
286 tcsh_number_t p2;
288 (*vp)++;
289 p2 = compat_expr ?
290 exp2b(vp, ignore) :
291 exp2c(vp, ignore);
292 etraci("exp2b p2", p2, vp);
293 if (compat_expr || !(ignore & TEXP_IGNORE))
294 p1 = (p1 & p2);
295 etraci("exp2b p1", p1, vp);
296 if (compat_expr)
297 break;
299 return (p1);
302 static tcsh_number_t
303 exp2c(Char ***vp, int ignore)
305 Char *p1 = exp3(vp, ignore);
306 Char *p2;
307 tcsh_number_t i;
309 cleanup_push(p1, xfree);
310 etracc("exp2c p1", p1, vp);
311 if ((i = isa(**vp, EQOP)) != 0) {
312 (*vp)++;
313 if (i == EQMATCH || i == NOTEQMATCH)
314 ignore |= TEXP_NOGLOB;
315 p2 = exp3(vp, ignore);
316 cleanup_push(p2, xfree);
317 etracc("exp2c p2", p2, vp);
318 if (!(ignore & TEXP_IGNORE))
319 switch ((int)i) {
321 case EQEQ:
322 i = eq(p1, p2);
323 break;
325 case NOTEQ:
326 i = !eq(p1, p2);
327 break;
329 case EQMATCH:
330 i = Gmatch(p1, p2);
331 break;
333 case NOTEQMATCH:
334 i = !Gmatch(p1, p2);
335 break;
337 cleanup_until(p1);
338 return (i);
340 i = egetn(p1);
341 cleanup_until(p1);
342 return (i);
345 static Char *
346 exp3(Char ***vp, int ignore)
348 Char *p1, *p2;
349 tcsh_number_t i;
351 p1 = exp3a(vp, ignore);
352 etracc("exp3 p1", p1, vp);
353 while ((i = isa(**vp, RELOP)) != 0) {
354 (*vp)++;
355 if (**vp && eq(**vp, STRequal))
356 i |= 1, (*vp)++;
357 cleanup_push(p1, xfree);
358 p2 = compat_expr ?
359 exp3(vp, ignore) :
360 exp3a(vp, ignore);
361 cleanup_push(p2, xfree);
362 etracc("exp3 p2", p2, vp);
363 if (!(ignore & TEXP_IGNORE))
364 switch ((int)i) {
366 case GTR:
367 i = egetn(p1) > egetn(p2);
368 break;
370 case GTR | 1:
371 i = egetn(p1) >= egetn(p2);
372 break;
374 case LSS:
375 i = egetn(p1) < egetn(p2);
376 break;
378 case LSS | 1:
379 i = egetn(p1) <= egetn(p2);
380 break;
382 cleanup_until(p1);
383 p1 = putn(i);
384 etracc("exp3 p1", p1, vp);
385 if (compat_expr)
386 break;
388 return (p1);
391 static Char *
392 exp3a(Char ***vp, int ignore)
394 Char *p1, *p2;
395 const Char *op;
396 tcsh_number_t i;
398 p1 = exp4(vp, ignore);
399 etracc("exp3a p1", p1, vp);
400 op = **vp;
401 if (op && any("<>", op[0]) && op[0] == op[1]) {
402 (*vp)++;
403 cleanup_push(p1, xfree);
404 p2 = compat_expr ?
405 exp3a(vp, ignore) :
406 exp4(vp, ignore);
407 cleanup_push(p2, xfree);
408 etracc("exp3a p2", p2, vp);
409 if (op[0] == '<')
410 i = egetn(p1) << egetn(p2);
411 else
412 i = egetn(p1) >> egetn(p2);
413 cleanup_until(p1);
414 p1 = putn(i);
415 etracc("exp3a p1", p1, vp);
417 return (p1);
420 static Char *
421 exp4(Char ***vp, int ignore)
423 Char *p1, *p2;
424 tcsh_number_t i = 0;
426 p1 = exp5(vp, ignore);
427 etracc("exp4 p1", p1, vp);
428 while (isa(**vp, ADDOP)) {
429 const Char *op = *(*vp)++;
431 cleanup_push(p1, xfree);
432 p2 = compat_expr ?
433 exp4(vp, ignore) :
434 exp5(vp, ignore);
435 cleanup_push(p2, xfree);
436 etracc("exp4 p2", p2, vp);
437 if (!(ignore & TEXP_IGNORE))
438 switch (op[0]) {
440 case '+':
441 i = egetn(p1) + egetn(p2);
442 break;
444 case '-':
445 i = egetn(p1) - egetn(p2);
446 break;
448 cleanup_until(p1);
449 p1 = putn(i);
450 etracc("exp4 p1", p1, vp);
451 if (compat_expr)
452 break;
454 return (p1);
457 static Char *
458 exp5(Char ***vp, int ignore)
460 Char *p1, *p2;
461 tcsh_number_t i = 0;
463 p1 = exp6(vp, ignore);
464 etracc("exp5 p1", p1, vp);
466 while (isa(**vp, MULOP)) {
467 const Char *op = *(*vp)++;
468 if ((ignore & TEXP_NOGLOB) != 0) {
470 * We are just trying to get the right side of
471 * a =~ or !~ operator
473 xfree(p1);
474 return Strsave(op);
477 cleanup_push(p1, xfree);
478 p2 = compat_expr ?
479 exp5(vp, ignore) :
480 exp6(vp, ignore);
481 cleanup_push(p2, xfree);
482 etracc("exp5 p2", p2, vp);
483 if (!(ignore & TEXP_IGNORE))
484 switch (op[0]) {
486 case '*':
487 i = egetn(p1) * egetn(p2);
488 break;
490 case '/':
491 i = egetn(p2);
492 if (i == 0)
493 stderror(ERR_DIV0);
494 i = egetn(p1) / i;
495 break;
497 case '%':
498 i = egetn(p2);
499 if (i == 0)
500 stderror(ERR_MOD0);
501 i = egetn(p1) % i;
502 break;
504 cleanup_until(p1);
505 p1 = putn(i);
506 etracc("exp5 p1", p1, vp);
507 if (compat_expr)
508 break;
510 return (p1);
513 static Char *
514 exp6(Char ***vp, int ignore)
516 tcsh_number_t ccode;
517 tcsh_number_t i = 0;
518 Char *cp;
520 if (**vp == 0)
521 stderror(ERR_NAME | ERR_EXPRESSION);
522 if (eq(**vp, STRbang)) {
523 (*vp)++;
524 cp = exp6(vp, ignore);
525 cleanup_push(cp, xfree);
526 etracc("exp6 ! cp", cp, vp);
527 i = egetn(cp);
528 cleanup_until(cp);
529 return (putn(!i));
531 if (eq(**vp, STRtilde)) {
532 (*vp)++;
533 cp = exp6(vp, ignore);
534 cleanup_push(cp, xfree);
535 etracc("exp6 ~ cp", cp, vp);
536 i = egetn(cp);
537 cleanup_until(cp);
538 return (putn(~i));
540 if (eq(**vp, STRLparen)) {
541 (*vp)++;
542 ccode = exp0(vp, ignore);
543 etraci("exp6 () ccode", ccode, vp);
544 if (**vp == 0 || ***vp != ')')
545 stderror(ERR_NAME | ERR_EXPRESSION);
546 (*vp)++;
547 return (putn(ccode));
549 if (eq(**vp, STRLbrace)) {
550 Char **v;
551 struct command faket;
552 Char *fakecom[2];
554 faket.t_dtyp = NODE_COMMAND;
555 faket.t_dflg = F_BACKQ;
556 faket.t_dcar = faket.t_dcdr = faket.t_dspr = NULL;
557 faket.t_dcom = fakecom;
558 fakecom[0] = STRfakecom;
559 fakecom[1] = NULL;
560 (*vp)++;
561 v = *vp;
562 for (;;) {
563 if (!**vp)
564 stderror(ERR_NAME | ERR_MISSING, '}');
565 if (eq(*(*vp)++, STRRbrace))
566 break;
568 if (ignore & TEXP_IGNORE)
569 return (Strsave(STRNULL));
570 psavejob();
571 cleanup_push(&faket, psavejob_cleanup); /* faket is only a marker */
572 if (pfork(&faket, -1) == 0) {
573 *--(*vp) = 0;
574 evalav(v);
575 exitstat();
577 pwait();
578 cleanup_until(&faket);
579 etraci("exp6 {} status", getstatus(), vp);
580 return putn(getstatus() == 0);
582 if (isa(**vp, ANYOP))
583 return (Strsave(STRNULL));
584 cp = *(*vp)++;
585 #ifdef convex
586 # define FILETESTS "erwxfdzoplstSXLbcugkmKR"
587 #else
588 # define FILETESTS "erwxfdzoplstSXLbcugkmK"
589 #endif /* convex */
590 #define FILEVALS "ZAMCDIUGNFPL"
591 if (*cp == '-' && (any(FILETESTS, cp[1]) || any(FILEVALS, cp[1])))
592 return(filetest(cp, vp, ignore));
593 etracc("exp6 default", cp, vp);
594 return (ignore & TEXP_NOGLOB ? Strsave(cp) : globone(cp, G_APPEND));
599 * Extended file tests
600 * From: John Rowe <rowe@excc.exeter.ac.uk>
602 Char *
603 filetest(Char *cp, Char ***vp, int ignore)
605 #ifdef convex
606 struct cvxstat stb, *st = NULL;
607 # define TCSH_STAT stat64
608 #else
609 # define TCSH_STAT stat
610 struct stat stb, *st = NULL;
611 #endif /* convex */
613 #ifdef S_IFLNK
614 # ifdef convex
615 struct cvxstat lstb, *lst = NULL;
616 # define TCSH_LSTAT lstat64
617 # else
618 # define TCSH_LSTAT lstat
619 struct stat lstb, *lst = NULL;
620 # endif /* convex */
621 char *filnam;
622 #endif /* S_IFLNK */
624 tcsh_number_t i = 0;
625 unsigned pmask = 0xffff;
626 int altout = 0;
627 Char *ft = cp, *dp, *ep, *strdev, *strino, *strF, *str, valtest = '\0',
628 *errval = STR0;
629 char *string, string0[22 + MB_LEN_MAX + 1]; /* space for 64 bit octal */
630 time_t footime;
631 struct passwd *pw;
632 struct group *gr;
634 while (any(FILETESTS, *++ft))
635 continue;
637 if (!*ft && *(ft - 1) == 'L')
638 --ft;
640 if (any(FILEVALS, *ft)) {
641 valtest = *ft++;
643 * Value tests return '-1' on failure as 0 is
644 * a legitimate value for many of them.
645 * 'F' returns ':' for compatibility.
647 errval = valtest == 'F' ? STRcolon : STRminus1;
649 if (valtest == 'P' && *ft >= '0' && *ft <= '7') {
650 pmask = (char) *ft - '0';
651 while ( *++ft >= '0' && *ft <= '7' )
652 pmask = 8 * pmask + ((char) *ft - '0');
654 if (Strcmp(ft, STRcolon) == 0 && any("AMCUGP", valtest)) {
655 altout = 1;
656 ++ft;
660 if (*ft || ft == cp + 1)
661 stderror(ERR_NAME | ERR_FILEINQ);
664 * Detect missing file names by checking for operator in the file name
665 * position. However, if an operator name appears there, we must make
666 * sure that there's no file by that name (e.g., "/") before announcing
667 * an error. Even this check isn't quite right, since it doesn't take
668 * globbing into account.
671 if (isa(**vp, ANYOP) && TCSH_STAT(short2str(**vp), &stb))
672 stderror(ERR_NAME | ERR_FILENAME);
674 dp = *(*vp)++;
675 if (ignore & TEXP_IGNORE)
676 return (Strsave(STRNULL));
677 if ((ignore & TEXP_NOGLOB) == 0) {
678 ep = globone(dp, G_APPEND);
679 } else {
680 ep = Strsave(dp);
682 cleanup_push(ep, xfree);
683 ft = &cp[1];
685 switch (*ft) {
687 case 'r':
688 i = !sh_access(ep, R_OK);
689 break;
691 case 'w':
692 i = !sh_access(ep, W_OK);
693 break;
695 case 'x':
696 i = !sh_access(ep, X_OK);
697 break;
699 case 'X': /* tcsh extension, name is an executable in the path
700 * or a tcsh builtin command
702 i = find_cmd(ep, 0);
703 break;
705 case 't': /* SGI extension, true when file is a tty */
706 i = isatty(atoi(short2str(ep)));
707 break;
709 default:
711 #ifdef S_IFLNK
712 if (tolower(*ft) == 'l') {
714 * avoid convex compiler bug.
716 if (!lst) {
717 lst = &lstb;
718 if (TCSH_LSTAT(short2str(ep), lst) == -1) {
719 cleanup_until(ep);
720 return (Strsave(errval));
723 if (*ft == 'L')
724 st = lst;
726 else
727 #endif /* S_IFLNK */
729 * avoid convex compiler bug.
731 if (!st) {
732 st = &stb;
733 if (TCSH_STAT(short2str(ep), st) == -1) {
734 cleanup_until(ep);
735 return (Strsave(errval));
739 switch (*ft) {
741 case 'f':
742 #ifdef S_ISREG
743 i = S_ISREG(st->st_mode);
744 #else /* !S_ISREG */
745 i = 0;
746 #endif /* S_ISREG */
747 break;
749 case 'd':
750 #ifdef S_ISDIR
751 i = S_ISDIR(st->st_mode);
752 #else /* !S_ISDIR */
753 i = 0;
754 #endif /* S_ISDIR */
755 break;
757 case 'p':
758 #ifdef S_ISFIFO
759 i = S_ISFIFO(st->st_mode);
760 #else /* !S_ISFIFO */
761 i = 0;
762 #endif /* S_ISFIFO */
763 break;
765 case 'm' :
766 #ifdef S_ISOFL
767 i = S_ISOFL(st->st_dm_mode);
768 #else /* !S_ISOFL */
769 i = 0;
770 #endif /* S_ISOFL */
771 break ;
773 case 'K' :
774 #ifdef S_ISOFL
775 i = stb.st_dm_key;
776 #else /* !S_ISOFL */
777 i = 0;
778 #endif /* S_ISOFL */
779 break ;
782 case 'l':
783 #ifdef S_ISLNK
784 i = S_ISLNK(lst->st_mode);
785 #else /* !S_ISLNK */
786 i = 0;
787 #endif /* S_ISLNK */
788 break;
790 case 'S':
791 # ifdef S_ISSOCK
792 i = S_ISSOCK(st->st_mode);
793 # else /* !S_ISSOCK */
794 i = 0;
795 # endif /* S_ISSOCK */
796 break;
798 case 'b':
799 #ifdef S_ISBLK
800 i = S_ISBLK(st->st_mode);
801 #else /* !S_ISBLK */
802 i = 0;
803 #endif /* S_ISBLK */
804 break;
806 case 'c':
807 #ifdef S_ISCHR
808 i = S_ISCHR(st->st_mode);
809 #else /* !S_ISCHR */
810 i = 0;
811 #endif /* S_ISCHR */
812 break;
814 case 'u':
815 i = (S_ISUID & st->st_mode) != 0;
816 break;
818 case 'g':
819 i = (S_ISGID & st->st_mode) != 0;
820 break;
822 case 'k':
823 i = (S_ISVTX & st->st_mode) != 0;
824 break;
826 case 'z':
827 i = st->st_size == 0;
828 break;
830 #ifdef convex
831 case 'R':
832 i = (stb.st_dmonflags & IMIGRATED) == IMIGRATED;
833 break;
834 #endif /* convex */
836 case 's':
837 i = stb.st_size != 0;
838 break;
840 case 'e':
841 i = 1;
842 break;
844 case 'o':
845 i = st->st_uid == uid;
846 break;
849 * Value operators are a tcsh extension.
852 case 'D':
853 i = (tcsh_number_t) st->st_dev;
854 break;
856 case 'I':
857 i = (tcsh_number_t) st->st_ino;
858 break;
860 case 'F':
861 strdev = putn( (int) st->st_dev);
862 strino = putn( (int) st->st_ino);
863 strF = xmalloc((2 + Strlen(strdev) + Strlen(strino))
864 * sizeof(Char));
865 (void) Strcat(Strcat(Strcpy(strF, strdev), STRcolon), strino);
866 xfree(strdev);
867 xfree(strino);
868 cleanup_until(ep);
869 return(strF);
871 case 'L':
872 if ( *(ft + 1) ) {
873 i = 1;
874 break;
876 #ifdef S_ISLNK
877 filnam = short2str(ep);
878 string = areadlink(filnam);
879 strF = string == NULL ? errval : str2short(string);
880 xfree(string);
881 cleanup_until(ep);
882 return(Strsave(strF));
884 #else /* !S_ISLNK */
885 i = 0;
886 break;
887 #endif /* S_ISLNK */
890 case 'N':
891 i = (tcsh_number_t) st->st_nlink;
892 break;
894 case 'P':
895 string = string0 + 1;
896 (void) xsnprintf(string, sizeof(string0) - 1, "%o",
897 pmask & (unsigned int)
898 ((S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID) & st->st_mode));
899 if (altout && *string != '0')
900 *--string = '0';
901 cleanup_until(ep);
902 return(Strsave(str2short(string)));
904 case 'U':
905 if (altout && (pw = xgetpwuid(st->st_uid))) {
906 cleanup_until(ep);
907 return(Strsave(str2short(pw->pw_name)));
909 i = (tcsh_number_t) st->st_uid;
910 break;
912 case 'G':
913 if (altout && (gr = xgetgrgid(st->st_gid))) {
914 cleanup_until(ep);
915 return(Strsave(str2short(gr->gr_name)));
917 i = (tcsh_number_t) st->st_gid;
918 break;
920 case 'Z':
921 i = (tcsh_number_t) st->st_size;
922 break;
924 case 'A': case 'M': case 'C':
925 footime = *ft == 'A' ? st->st_atime :
926 *ft == 'M' ? st->st_mtime : st->st_ctime;
927 if (altout) {
928 strF = str2short(ctime(&footime));
929 if ((str = Strchr(strF, '\n')) != NULL)
930 *str = (Char) '\0';
931 cleanup_until(ep);
932 return(Strsave(strF));
934 i = (tcsh_number_t) footime;
935 break;
939 while (*++ft && i);
940 etraci("exp6 -? i", i, vp);
941 cleanup_until(ep);
942 return (putn(i));
946 static void
947 evalav(Char **v)
949 struct wordent paraml1;
950 struct wordent *hp = &paraml1;
951 struct command *t;
952 struct wordent *wdp = hp;
954 setstatus(0);
955 initlex(hp);
956 while (*v) {
957 struct wordent *new = xcalloc(1, sizeof *wdp);
959 new->prev = wdp;
960 new->next = hp;
961 wdp->next = new;
962 wdp = new;
963 wdp->word = Strsave(*v++);
965 hp->prev = wdp;
966 cleanup_push(&paraml1, lex_cleanup);
967 alias(&paraml1);
968 t = syntax(paraml1.next, &paraml1, 0);
969 cleanup_push(t, syntax_cleanup);
970 if (seterr)
971 stderror(ERR_OLD);
972 execute(t, -1, NULL, NULL, TRUE);
973 cleanup_until(&paraml1);
976 static int
977 isa(Char *cp, int what)
979 if (cp == 0)
980 return ((what & RESTOP) != 0);
981 if (*cp == '\0')
982 return 0;
983 if (cp[1] == 0) {
984 if (what & ADDOP && (*cp == '+' || *cp == '-'))
985 return (1);
986 if (what & MULOP && (*cp == '*' || *cp == '/' || *cp == '%'))
987 return (1);
988 if (what & RESTOP && (*cp == '(' || *cp == ')' || *cp == '!' ||
989 *cp == '~' || *cp == '^' || *cp == '"'))
990 return (1);
992 else if (cp[2] == 0) {
993 if (what & RESTOP) {
994 if (cp[0] == '|' && cp[1] == '&')
995 return (1);
996 if (cp[0] == '<' && cp[1] == '<')
997 return (1);
998 if (cp[0] == '>' && cp[1] == '>')
999 return (1);
1001 if (what & EQOP) {
1002 if (cp[0] == '=') {
1003 if (cp[1] == '=')
1004 return (EQEQ);
1005 if (cp[1] == '~')
1006 return (EQMATCH);
1008 else if (cp[0] == '!') {
1009 if (cp[1] == '=')
1010 return (NOTEQ);
1011 if (cp[1] == '~')
1012 return (NOTEQMATCH);
1016 if (what & RELOP) {
1017 if (*cp == '<')
1018 return (LSS);
1019 if (*cp == '>')
1020 return (GTR);
1022 return (0);
1025 static tcsh_number_t
1026 egetn(const Char *cp)
1028 if (*cp && *cp != '-' && !Isdigit(*cp))
1029 stderror(ERR_NAME | ERR_EXPRESSION);
1030 return (getn(cp));
1033 /* Phew! */
1035 #ifdef EDEBUG
1036 static void
1037 etraci(const char *str, tcsh_number_t i, Char ***vp)
1039 #ifdef HAVE_LONG_LONG
1040 xprintf("%s=%lld\t", str, i);
1041 #else
1042 xprintf("%s=%ld\t", str, i);
1043 #endif
1044 blkpr(*vp);
1045 xputchar('\n');
1047 static void
1048 etracc(const char *str, const Char *cp, Char ***vp)
1050 xprintf("%s=%S\t", str, cp);
1051 blkpr(*vp);
1052 xputchar('\n');
1054 #endif /* EDEBUG */