wpa_supplicant: Adjust master for the 2.9 upgrade.
[dragonfly.git] / contrib / tcsh-6 / sh.exp.c
blob9d85e0bd159c0b8ce0c7ec5f43b5835e10df6d1c
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 TEXP_IGNORE 1 /* in ignore, it means to ignore value, just parse */
40 #define TEXP_NOGLOB 2 /* in ignore, it means not to globone */
42 #define ADDOP 1
43 #define MULOP 2
44 #define EQOP 4
45 #define RELOP 8
46 #define RESTOP 16
47 #define ANYOP 31
49 #define EQEQ 1
50 #define GTR 2
51 #define LSS 4
52 #define NOTEQ 6
53 #define EQMATCH 7
54 #define NOTEQMATCH 8
56 static int sh_access (const Char *, int);
57 static tcsh_number_t exp1 (Char ***, int);
58 static tcsh_number_t exp2x (Char ***, int);
59 static tcsh_number_t exp2a (Char ***, int);
60 static tcsh_number_t exp2b (Char ***, int);
61 static tcsh_number_t exp2c (Char ***, int);
62 static Char *exp3 (Char ***, int);
63 static Char *exp3a (Char ***, int);
64 static Char *exp4 (Char ***, int);
65 static Char *exp5 (Char ***, int);
66 static Char *exp6 (Char ***, int);
67 static void evalav (Char **);
68 static int isa (Char *, int);
69 static tcsh_number_t egetn (const Char *);
71 #ifdef EDEBUG
72 static void etracc (const char *, const Char *, Char ***);
73 static void etraci (const char *, tcsh_number_t, Char ***);
74 #else /* !EDEBUG */
75 #define etracc(A, B, C) ((void)0)
76 #define etraci(A, B, C) ((void)0)
77 #endif /* !EDEBUG */
80 * shell access function according to POSIX and non POSIX
81 * From Beto Appleton (beto@aixwiz.aix.ibm.com)
83 static int
84 sh_access(const Char *fname, int mode)
86 #if defined(POSIX) && !defined(USE_ACCESS)
87 struct stat statb;
88 #endif /* POSIX */
89 char *name = short2str(fname);
91 if (*name == '\0')
92 return 1;
94 #if !defined(POSIX) || defined(USE_ACCESS)
95 return access(name, mode);
96 #else /* POSIX */
99 * POSIX 1003.2-d11.2
100 * -r file True if file exists and is readable.
101 * -w file True if file exists and is writable.
102 * True shall indicate only that the write flag is on.
103 * The file shall not be writable on a read-only file
104 * system even if this test indicates true.
105 * -x file True if file exists and is executable.
106 * True shall indicate only that the execute flag is on.
107 * If file is a directory, true indicates that the file
108 * can be searched.
110 if (mode != W_OK && mode != X_OK)
111 return access(name, mode);
113 if (stat(name, &statb) == -1)
114 return 1;
116 if (access(name, mode) == 0) {
117 #ifdef S_ISDIR
118 if (S_ISDIR(statb.st_mode) && mode == X_OK)
119 return 0;
120 #endif /* S_ISDIR */
122 /* root needs permission for someone */
123 switch (mode) {
124 case W_OK:
125 mode = S_IWUSR | S_IWGRP | S_IWOTH;
126 break;
127 case X_OK:
128 mode = S_IXUSR | S_IXGRP | S_IXOTH;
129 break;
130 default:
131 abort();
132 break;
137 else if (euid == statb.st_uid)
138 mode <<= 6;
140 else if (egid == statb.st_gid)
141 mode <<= 3;
143 # ifdef NGROUPS_MAX
144 else {
145 /* you can be in several groups */
146 long n;
147 GETGROUPS_T *groups;
150 * Try these things to find a positive maximum groups value:
151 * 1) sysconf(_SC_NGROUPS_MAX)
152 * 2) NGROUPS_MAX
153 * 3) getgroups(0, unused)
154 * Then allocate and scan the groups array if one of these worked.
156 # if defined (HAVE_SYSCONF) && defined (_SC_NGROUPS_MAX)
157 if ((n = sysconf(_SC_NGROUPS_MAX)) == -1)
158 # endif /* _SC_NGROUPS_MAX */
159 n = NGROUPS_MAX;
160 if (n <= 0)
161 n = getgroups(0, (GETGROUPS_T *) NULL);
163 if (n > 0) {
164 groups = xmalloc(n * sizeof(*groups));
165 n = getgroups((int) n, groups);
166 while (--n >= 0)
167 if (groups[n] == statb.st_gid) {
168 mode <<= 3;
169 break;
171 xfree(groups);
174 # endif /* NGROUPS_MAX */
176 if (statb.st_mode & mode)
177 return 0;
178 else
179 return 1;
180 #endif /* !POSIX */
183 tcsh_number_t
184 expr(Char ***vp)
186 return (exp0(vp, 0));
189 tcsh_number_t
190 exp0(Char ***vp, int ignore)
192 tcsh_number_t p1 = exp1(vp, ignore);
194 etraci("exp0 p1", p1, vp);
195 while (**vp && eq(**vp, STRor2)) {
196 int p2;
198 (*vp)++;
200 p2 = compat_expr ?
201 exp0(vp, (ignore & TEXP_IGNORE) || p1) :
202 exp1(vp, (ignore & TEXP_IGNORE) || p1);
203 if (compat_expr || !(ignore & TEXP_IGNORE))
204 p1 = (p1 || p2);
205 etraci("exp0 p1", p1, vp);
206 if (compat_expr)
207 break;
209 return (p1);
212 static tcsh_number_t
213 exp1(Char ***vp, int ignore)
215 tcsh_number_t p1 = exp2x(vp, ignore);
217 etraci("exp1 p1", p1, vp);
218 while (**vp && eq(**vp, STRand2)) {
219 tcsh_number_t p2;
221 (*vp)++;
222 p2 = compat_expr ?
223 exp1(vp, (ignore & TEXP_IGNORE) || !p1) :
224 exp2x(vp, (ignore & TEXP_IGNORE) || !p1);
226 etraci("exp1 p2", p2, vp);
227 if (compat_expr || !(ignore & TEXP_IGNORE))
228 p1 = (p1 && p2);
229 etraci("exp1 p1", p1, vp);
230 if (compat_expr)
231 break;
233 return (p1);
236 static tcsh_number_t
237 exp2x(Char ***vp, int ignore)
239 tcsh_number_t p1 = exp2a(vp, ignore);
241 etraci("exp2x p1", p1, vp);
242 while (**vp && eq(**vp, STRor)) {
243 tcsh_number_t p2;
245 (*vp)++;
246 p2 = compat_expr ?
247 exp2x(vp, ignore) :
248 exp2a(vp, ignore);
249 etraci("exp2x p2", p2, vp);
250 if (compat_expr || !(ignore & TEXP_IGNORE))
251 p1 = (p1 | p2);
252 etraci("exp2x p1", p1, vp);
253 if (compat_expr)
254 break;
256 return (p1);
259 static tcsh_number_t
260 exp2a(Char ***vp, int ignore)
262 tcsh_number_t p1 = exp2b(vp, ignore);
264 etraci("exp2a p1", p1, vp);
265 while (**vp && eq(**vp, STRcaret)) {
266 tcsh_number_t p2;
268 (*vp)++;
269 p2 = compat_expr ?
270 exp2a(vp, ignore) :
271 exp2b(vp, ignore);
272 etraci("exp2a p2", p2, vp);
273 if (compat_expr || !(ignore & TEXP_IGNORE))
274 p1 = (p1 ^ p2);
275 etraci("exp2a p1", p1, vp);
276 if (compat_expr)
277 break;
279 return (p1);
282 static tcsh_number_t
283 exp2b(Char ***vp, int ignore)
285 tcsh_number_t p1 = exp2c(vp, ignore);
287 etraci("exp2b p1", p1, vp);
288 while (**vp && eq(**vp, STRand)) {
289 tcsh_number_t p2;
291 (*vp)++;
292 p2 = compat_expr ?
293 exp2b(vp, ignore) :
294 exp2c(vp, ignore);
295 etraci("exp2b p2", p2, vp);
296 if (compat_expr || !(ignore & TEXP_IGNORE))
297 p1 = (p1 & p2);
298 etraci("exp2b p1", p1, vp);
299 if (compat_expr)
300 break;
302 return (p1);
305 static tcsh_number_t
306 exp2c(Char ***vp, int ignore)
308 Char *p1 = exp3(vp, ignore);
309 Char *p2;
310 tcsh_number_t i;
312 cleanup_push(p1, xfree);
313 etracc("exp2c p1", p1, vp);
314 if ((i = isa(**vp, EQOP)) != 0) {
315 (*vp)++;
316 if (i == EQMATCH || i == NOTEQMATCH)
317 ignore |= TEXP_NOGLOB;
318 p2 = exp3(vp, ignore);
319 cleanup_push(p2, xfree);
320 etracc("exp2c p2", p2, vp);
321 if (!(ignore & TEXP_IGNORE))
322 switch ((int)i) {
324 case EQEQ:
325 i = eq(p1, p2);
326 break;
328 case NOTEQ:
329 i = !eq(p1, p2);
330 break;
332 case EQMATCH:
333 i = Gmatch(p1, p2);
334 break;
336 case NOTEQMATCH:
337 i = !Gmatch(p1, p2);
338 break;
340 cleanup_until(p1);
341 return (i);
343 i = egetn(p1);
344 cleanup_until(p1);
345 return (i);
348 static Char *
349 exp3(Char ***vp, int ignore)
351 Char *p1, *p2;
352 tcsh_number_t i;
354 p1 = exp3a(vp, ignore);
355 etracc("exp3 p1", p1, vp);
356 while ((i = isa(**vp, RELOP)) != 0) {
357 (*vp)++;
358 if (**vp && eq(**vp, STRequal))
359 i |= 1, (*vp)++;
360 cleanup_push(p1, xfree);
361 p2 = compat_expr ?
362 exp3(vp, ignore) :
363 exp3a(vp, ignore);
364 cleanup_push(p2, xfree);
365 etracc("exp3 p2", p2, vp);
366 if (!(ignore & TEXP_IGNORE))
367 switch ((int)i) {
369 case GTR:
370 i = egetn(p1) > egetn(p2);
371 break;
373 case GTR | 1:
374 i = egetn(p1) >= egetn(p2);
375 break;
377 case LSS:
378 i = egetn(p1) < egetn(p2);
379 break;
381 case LSS | 1:
382 i = egetn(p1) <= egetn(p2);
383 break;
385 cleanup_until(p1);
386 p1 = putn(i);
387 etracc("exp3 p1", p1, vp);
388 if (compat_expr)
389 break;
391 return (p1);
394 static Char *
395 exp3a(Char ***vp, int ignore)
397 Char *p1, *p2;
398 const Char *op;
399 tcsh_number_t i;
401 p1 = exp4(vp, ignore);
402 etracc("exp3a p1", p1, vp);
403 op = **vp;
404 if (op && any("<>", op[0]) && op[0] == op[1]) {
405 (*vp)++;
406 cleanup_push(p1, xfree);
407 p2 = compat_expr ?
408 exp3a(vp, ignore) :
409 exp4(vp, ignore);
410 cleanup_push(p2, xfree);
411 etracc("exp3a p2", p2, vp);
412 if (op[0] == '<')
413 i = egetn(p1) << egetn(p2);
414 else
415 i = egetn(p1) >> egetn(p2);
416 cleanup_until(p1);
417 p1 = putn(i);
418 etracc("exp3a p1", p1, vp);
420 return (p1);
423 static Char *
424 exp4(Char ***vp, int ignore)
426 Char *p1, *p2;
427 tcsh_number_t i = 0;
429 p1 = exp5(vp, ignore);
430 etracc("exp4 p1", p1, vp);
431 while (isa(**vp, ADDOP)) {
432 const Char *op = *(*vp)++;
434 cleanup_push(p1, xfree);
435 p2 = compat_expr ?
436 exp4(vp, ignore) :
437 exp5(vp, ignore);
438 cleanup_push(p2, xfree);
439 etracc("exp4 p2", p2, vp);
440 if (!(ignore & TEXP_IGNORE))
441 switch (op[0]) {
443 case '+':
444 i = egetn(p1) + egetn(p2);
445 break;
447 case '-':
448 i = egetn(p1) - egetn(p2);
449 break;
451 cleanup_until(p1);
452 p1 = putn(i);
453 etracc("exp4 p1", p1, vp);
454 if (compat_expr)
455 break;
457 return (p1);
460 static Char *
461 exp5(Char ***vp, int ignore)
463 Char *p1, *p2;
464 tcsh_number_t i = 0;
466 p1 = exp6(vp, ignore);
467 etracc("exp5 p1", p1, vp);
469 while (isa(**vp, MULOP)) {
470 const Char *op = *(*vp)++;
471 if ((ignore & TEXP_NOGLOB) != 0) {
473 * We are just trying to get the right side of
474 * a =~ or !~ operator
476 xfree(p1);
477 return Strsave(op);
480 cleanup_push(p1, xfree);
481 p2 = compat_expr ?
482 exp5(vp, ignore) :
483 exp6(vp, ignore);
484 cleanup_push(p2, xfree);
485 etracc("exp5 p2", p2, vp);
486 if (!(ignore & TEXP_IGNORE))
487 switch (op[0]) {
489 case '*':
490 i = egetn(p1) * egetn(p2);
491 break;
493 case '/':
494 i = egetn(p2);
495 if (i == 0)
496 stderror(ERR_DIV0);
497 i = egetn(p1) / i;
498 break;
500 case '%':
501 i = egetn(p2);
502 if (i == 0)
503 stderror(ERR_MOD0);
504 i = egetn(p1) % i;
505 break;
507 cleanup_until(p1);
508 p1 = putn(i);
509 etracc("exp5 p1", p1, vp);
510 if (compat_expr)
511 break;
513 return (p1);
516 static Char *
517 exp6(Char ***vp, int ignore)
519 tcsh_number_t ccode;
520 tcsh_number_t i = 0;
521 Char *cp;
523 if (**vp == 0)
524 stderror(ERR_NAME | ERR_EXPRESSION);
525 if (eq(**vp, STRbang)) {
526 (*vp)++;
527 cp = exp6(vp, ignore);
528 cleanup_push(cp, xfree);
529 etracc("exp6 ! cp", cp, vp);
530 i = egetn(cp);
531 cleanup_until(cp);
532 return (putn(!i));
534 if (eq(**vp, STRtilde)) {
535 (*vp)++;
536 cp = exp6(vp, ignore);
537 cleanup_push(cp, xfree);
538 etracc("exp6 ~ cp", cp, vp);
539 i = egetn(cp);
540 cleanup_until(cp);
541 return (putn(~i));
543 if (eq(**vp, STRLparen)) {
544 (*vp)++;
545 ccode = exp0(vp, ignore);
546 etraci("exp6 () ccode", ccode, vp);
547 if (**vp == 0 || ***vp != ')')
548 stderror(ERR_NAME | ERR_EXPRESSION);
549 (*vp)++;
550 return (putn(ccode));
552 if (eq(**vp, STRLbrace)) {
553 Char **v;
554 struct command faket;
555 Char *fakecom[2];
557 faket.t_dtyp = NODE_COMMAND;
558 faket.t_dflg = F_BACKQ;
559 faket.t_dcar = faket.t_dcdr = faket.t_dspr = NULL;
560 faket.t_dcom = fakecom;
561 fakecom[0] = STRfakecom;
562 fakecom[1] = NULL;
563 (*vp)++;
564 v = *vp;
565 for (;;) {
566 if (!**vp)
567 stderror(ERR_NAME | ERR_MISSING, '}');
568 if (eq(*(*vp)++, STRRbrace))
569 break;
571 if (ignore & TEXP_IGNORE)
572 return (Strsave(STRNULL));
573 psavejob();
574 cleanup_push(&faket, psavejob_cleanup); /* faket is only a marker */
575 if (pfork(&faket, -1) == 0) {
576 *--(*vp) = 0;
577 evalav(v);
578 exitstat();
580 pwait();
581 cleanup_until(&faket);
582 etraci("exp6 {} status", egetn(varval(STRstatus)), vp);
583 return (putn(egetn(varval(STRstatus)) == 0));
585 if (isa(**vp, ANYOP))
586 return (Strsave(STRNULL));
587 cp = *(*vp)++;
588 #ifdef convex
589 # define FILETESTS "erwxfdzoplstSXLbcugkmKR"
590 #else
591 # define FILETESTS "erwxfdzoplstSXLbcugkmK"
592 #endif /* convex */
593 #define FILEVALS "ZAMCDIUGNFPL"
594 if (*cp == '-' && (any(FILETESTS, cp[1]) || any(FILEVALS, cp[1])))
595 return(filetest(cp, vp, ignore));
596 etracc("exp6 default", cp, vp);
597 return (ignore & TEXP_NOGLOB ? Strsave(cp) : globone(cp, G_APPEND));
602 * Extended file tests
603 * From: John Rowe <rowe@excc.exeter.ac.uk>
605 Char *
606 filetest(Char *cp, Char ***vp, int ignore)
608 #ifdef convex
609 struct cvxstat stb, *st = NULL;
610 # define TCSH_STAT stat64
611 #else
612 # define TCSH_STAT stat
613 struct stat stb, *st = NULL;
614 #endif /* convex */
616 #ifdef S_IFLNK
617 # ifdef convex
618 struct cvxstat lstb, *lst = NULL;
619 # define TCSH_LSTAT lstat64
620 # else
621 # define TCSH_LSTAT lstat
622 struct stat lstb, *lst = NULL;
623 # endif /* convex */
624 char *filnam;
625 #endif /* S_IFLNK */
627 tcsh_number_t i = 0;
628 unsigned pmask = 0xffff;
629 int altout = 0;
630 Char *ft = cp, *dp, *ep, *strdev, *strino, *strF, *str, valtest = '\0',
631 *errval = STR0;
632 char *string, string0[22 + MB_LEN_MAX + 1]; /* space for 64 bit octal */
633 time_t footime;
634 struct passwd *pw;
635 struct group *gr;
637 while(any(FILETESTS, *++ft))
638 continue;
640 if (!*ft && *(ft - 1) == 'L')
641 --ft;
643 if (any(FILEVALS, *ft)) {
644 valtest = *ft++;
646 * Value tests return '-1' on failure as 0 is
647 * a legitimate value for many of them.
648 * 'F' returns ':' for compatibility.
650 errval = valtest == 'F' ? STRcolon : STRminus1;
652 if (valtest == 'P' && *ft >= '0' && *ft <= '7') {
653 pmask = (char) *ft - '0';
654 while ( *++ft >= '0' && *ft <= '7' )
655 pmask = 8 * pmask + ((char) *ft - '0');
657 if (Strcmp(ft, STRcolon) == 0 && any("AMCUGP", valtest)) {
658 altout = 1;
659 ++ft;
663 if (*ft || ft == cp + 1)
664 stderror(ERR_NAME | ERR_FILEINQ);
667 * Detect missing file names by checking for operator in the file name
668 * position. However, if an operator name appears there, we must make
669 * sure that there's no file by that name (e.g., "/") before announcing
670 * an error. Even this check isn't quite right, since it doesn't take
671 * globbing into account.
674 if (isa(**vp, ANYOP) && TCSH_STAT(short2str(**vp), &stb))
675 stderror(ERR_NAME | ERR_FILENAME);
677 dp = *(*vp)++;
678 if (ignore & TEXP_IGNORE)
679 return (Strsave(STRNULL));
680 ep = globone(dp, G_APPEND);
681 cleanup_push(ep, xfree);
682 ft = &cp[1];
684 switch (*ft) {
686 case 'r':
687 i = !sh_access(ep, R_OK);
688 break;
690 case 'w':
691 i = !sh_access(ep, W_OK);
692 break;
694 case 'x':
695 i = !sh_access(ep, X_OK);
696 break;
698 case 'X': /* tcsh extension, name is an executable in the path
699 * or a tcsh builtin command
701 i = find_cmd(ep, 0);
702 break;
704 case 't': /* SGI extension, true when file is a tty */
705 i = isatty(atoi(short2str(ep)));
706 break;
708 default:
710 #ifdef S_IFLNK
711 if (tolower(*ft) == 'l') {
713 * avoid convex compiler bug.
715 if (!lst) {
716 lst = &lstb;
717 if (TCSH_LSTAT(short2str(ep), lst) == -1) {
718 cleanup_until(ep);
719 return (Strsave(errval));
722 if (*ft == 'L')
723 st = lst;
725 else
726 #endif /* S_IFLNK */
728 * avoid convex compiler bug.
730 if (!st) {
731 st = &stb;
732 if (TCSH_STAT(short2str(ep), st) == -1) {
733 cleanup_until(ep);
734 return (Strsave(errval));
738 switch (*ft) {
740 case 'f':
741 #ifdef S_ISREG
742 i = S_ISREG(st->st_mode);
743 #else /* !S_ISREG */
744 i = 0;
745 #endif /* S_ISREG */
746 break;
748 case 'd':
749 #ifdef S_ISDIR
750 i = S_ISDIR(st->st_mode);
751 #else /* !S_ISDIR */
752 i = 0;
753 #endif /* S_ISDIR */
754 break;
756 case 'p':
757 #ifdef S_ISFIFO
758 i = S_ISFIFO(st->st_mode);
759 #else /* !S_ISFIFO */
760 i = 0;
761 #endif /* S_ISFIFO */
762 break;
764 case 'm' :
765 #ifdef S_ISOFL
766 i = S_ISOFL(st->st_dm_mode);
767 #else /* !S_ISOFL */
768 i = 0;
769 #endif /* S_ISOFL */
770 break ;
772 case 'K' :
773 #ifdef S_ISOFL
774 i = stb.st_dm_key;
775 #else /* !S_ISOFL */
776 i = 0;
777 #endif /* S_ISOFL */
778 break ;
781 case 'l':
782 #ifdef S_ISLNK
783 i = S_ISLNK(lst->st_mode);
784 #else /* !S_ISLNK */
785 i = 0;
786 #endif /* S_ISLNK */
787 break;
789 case 'S':
790 # ifdef S_ISSOCK
791 i = S_ISSOCK(st->st_mode);
792 # else /* !S_ISSOCK */
793 i = 0;
794 # endif /* S_ISSOCK */
795 break;
797 case 'b':
798 #ifdef S_ISBLK
799 i = S_ISBLK(st->st_mode);
800 #else /* !S_ISBLK */
801 i = 0;
802 #endif /* S_ISBLK */
803 break;
805 case 'c':
806 #ifdef S_ISCHR
807 i = S_ISCHR(st->st_mode);
808 #else /* !S_ISCHR */
809 i = 0;
810 #endif /* S_ISCHR */
811 break;
813 case 'u':
814 i = (S_ISUID & st->st_mode) != 0;
815 break;
817 case 'g':
818 i = (S_ISGID & st->st_mode) != 0;
819 break;
821 case 'k':
822 i = (S_ISVTX & st->st_mode) != 0;
823 break;
825 case 'z':
826 i = st->st_size == 0;
827 break;
829 #ifdef convex
830 case 'R':
831 i = (stb.st_dmonflags & IMIGRATED) == IMIGRATED;
832 break;
833 #endif /* convex */
835 case 's':
836 i = stb.st_size != 0;
837 break;
839 case 'e':
840 i = 1;
841 break;
843 case 'o':
844 i = st->st_uid == uid;
845 break;
848 * Value operators are a tcsh extension.
851 case 'D':
852 i = (tcsh_number_t) st->st_dev;
853 break;
855 case 'I':
856 i = (tcsh_number_t) st->st_ino;
857 break;
859 case 'F':
860 strdev = putn( (int) st->st_dev);
861 strino = putn( (int) st->st_ino);
862 strF = xmalloc((2 + Strlen(strdev) + Strlen(strino))
863 * sizeof(Char));
864 (void) Strcat(Strcat(Strcpy(strF, strdev), STRcolon), strino);
865 xfree(strdev);
866 xfree(strino);
867 cleanup_until(ep);
868 return(strF);
870 case 'L':
871 if ( *(ft + 1) ) {
872 i = 1;
873 break;
875 #ifdef S_ISLNK
876 filnam = short2str(ep);
877 string = areadlink(filnam);
878 strF = string == NULL ? errval : str2short(string);
879 xfree(string);
880 cleanup_until(ep);
881 return(Strsave(strF));
883 #else /* !S_ISLNK */
884 i = 0;
885 break;
886 #endif /* S_ISLNK */
889 case 'N':
890 i = (tcsh_number_t) st->st_nlink;
891 break;
893 case 'P':
894 string = string0 + 1;
895 (void) xsnprintf(string, sizeof(string0) - 1, "%o",
896 pmask & (unsigned int)
897 ((S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID) & st->st_mode));
898 if (altout && *string != '0')
899 *--string = '0';
900 cleanup_until(ep);
901 return(Strsave(str2short(string)));
903 case 'U':
904 if (altout && (pw = xgetpwuid(st->st_uid))) {
905 cleanup_until(ep);
906 return(Strsave(str2short(pw->pw_name)));
908 i = (tcsh_number_t) st->st_uid;
909 break;
911 case 'G':
912 if (altout && (gr = xgetgrgid(st->st_gid))) {
913 cleanup_until(ep);
914 return(Strsave(str2short(gr->gr_name)));
916 i = (tcsh_number_t) st->st_gid;
917 break;
919 case 'Z':
920 i = (tcsh_number_t) st->st_size;
921 break;
923 case 'A': case 'M': case 'C':
924 footime = *ft == 'A' ? st->st_atime :
925 *ft == 'M' ? st->st_mtime : st->st_ctime;
926 if (altout) {
927 strF = str2short(ctime(&footime));
928 if ((str = Strchr(strF, '\n')) != NULL)
929 *str = (Char) '\0';
930 cleanup_until(ep);
931 return(Strsave(strF));
933 i = (tcsh_number_t) footime;
934 break;
938 while (*++ft && i);
939 etraci("exp6 -? i", i, vp);
940 cleanup_until(ep);
941 return (putn(i));
945 static void
946 evalav(Char **v)
948 struct wordent paraml1;
949 struct wordent *hp = &paraml1;
950 struct command *t;
951 struct wordent *wdp = hp;
953 setcopy(STRstatus, STR0, VAR_READWRITE);
954 initlex(hp);
955 while (*v) {
956 struct wordent *new = xcalloc(1, sizeof *wdp);
958 new->prev = wdp;
959 new->next = hp;
960 wdp->next = new;
961 wdp = new;
962 wdp->word = Strsave(*v++);
964 hp->prev = wdp;
965 cleanup_push(&paraml1, lex_cleanup);
966 alias(&paraml1);
967 t = syntax(paraml1.next, &paraml1, 0);
968 cleanup_push(t, syntax_cleanup);
969 if (seterr)
970 stderror(ERR_OLD);
971 execute(t, -1, NULL, NULL, TRUE);
972 cleanup_until(&paraml1);
975 static int
976 isa(Char *cp, int what)
978 if (cp == 0)
979 return ((what & RESTOP) != 0);
980 if (*cp == '\0')
981 return 0;
982 if (cp[1] == 0) {
983 if (what & ADDOP && (*cp == '+' || *cp == '-'))
984 return (1);
985 if (what & MULOP && (*cp == '*' || *cp == '/' || *cp == '%'))
986 return (1);
987 if (what & RESTOP && (*cp == '(' || *cp == ')' || *cp == '!' ||
988 *cp == '~' || *cp == '^' || *cp == '"'))
989 return (1);
991 else if (cp[2] == 0) {
992 if (what & RESTOP) {
993 if (cp[0] == '|' && cp[1] == '&')
994 return (1);
995 if (cp[0] == '<' && cp[1] == '<')
996 return (1);
997 if (cp[0] == '>' && cp[1] == '>')
998 return (1);
1000 if (what & EQOP) {
1001 if (cp[0] == '=') {
1002 if (cp[1] == '=')
1003 return (EQEQ);
1004 if (cp[1] == '~')
1005 return (EQMATCH);
1007 else if (cp[0] == '!') {
1008 if (cp[1] == '=')
1009 return (NOTEQ);
1010 if (cp[1] == '~')
1011 return (NOTEQMATCH);
1015 if (what & RELOP) {
1016 if (*cp == '<')
1017 return (LSS);
1018 if (*cp == '>')
1019 return (GTR);
1021 return (0);
1024 static tcsh_number_t
1025 egetn(const Char *cp)
1027 if (*cp && *cp != '-' && !Isdigit(*cp))
1028 stderror(ERR_NAME | ERR_EXPRESSION);
1029 return (getn(cp));
1032 /* Phew! */
1034 #ifdef EDEBUG
1035 static void
1036 etraci(const char *str, tcsh_number_t i, Char ***vp)
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');
1046 static void
1047 etracc(const char *str, const Char *cp, Char ***vp)
1049 xprintf("%s=%S\t", str, cp);
1050 blkpr(*vp);
1051 xputchar('\n');
1053 #endif /* EDEBUG */