source: trunk/third/tcsh/sh.exp.c @ 22036

Revision 22036, 21.5 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r22035, which included commits to RCS files with non-trunk default branches.
Line 
1/* $Header: /afs/dev.mit.edu/source/repository/third/tcsh/sh.exp.c,v 1.1.1.3 2005-06-03 14:35:17 ghudson Exp $ */
2/*
3 * sh.exp.c: Expression evaluations
4 */
5/*-
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33#include "sh.h"
34
35RCSID("$Id: sh.exp.c,v 1.1.1.3 2005-06-03 14:35:17 ghudson Exp $")
36
37#include "tw.h"
38
39/*
40 * C shell
41 */
42
43#define TEXP_IGNORE 1   /* in ignore, it means to ignore value, just parse */
44#define TEXP_NOGLOB 2   /* in ignore, it means not to globone */
45
46#define ADDOP   1
47#define MULOP   2
48#define EQOP    4
49#define RELOP   8
50#define RESTOP  16
51#define ANYOP   31
52
53#define EQEQ    1
54#define GTR     2
55#define LSS     4
56#define NOTEQ   6
57#define EQMATCH 7
58#define NOTEQMATCH 8
59
60static  int      sh_access      __P((Char *, int));
61static  int      exp1           __P((Char ***, int));
62static  int      exp2x          __P((Char ***, int));
63static  int      exp2a          __P((Char ***, int));
64static  int      exp2b          __P((Char ***, int));
65static  int      exp2c          __P((Char ***, int));
66static  Char    *exp3           __P((Char ***, int));
67static  Char    *exp3a          __P((Char ***, int));
68static  Char    *exp4           __P((Char ***, int));
69static  Char    *exp5           __P((Char ***, int));
70static  Char    *exp6           __P((Char ***, int));
71static  void     evalav         __P((Char **));
72static  int      isa            __P((Char *, int));
73static  int      egetn          __P((Char *));
74
75
76#ifdef EDEBUG
77static  void     etracc         __P((char *, Char *, Char ***));
78static  void     etraci         __P((char *, int, Char ***));
79#endif /* EDEBUG */
80
81
82/*
83 * shell access function according to POSIX and non POSIX
84 * From Beto Appleton (beto@aixwiz.aix.ibm.com)
85 */
86static int
87sh_access(fname, mode)
88    Char *fname;
89    int mode;
90{
91#if defined(POSIX) && !defined(USE_ACCESS)
92    struct stat     statb;
93#endif /* POSIX */
94    char *name = short2str(fname);
95
96    if (*name == '\0')
97        return 1;
98
99#if !defined(POSIX) || defined(USE_ACCESS)
100    return access(name, mode);
101#else /* POSIX */
102
103    /*
104     * POSIX 1003.2-d11.2
105     *  -r file         True if file exists and is readable.
106     *  -w file         True if file exists and is writable.
107     *                  True shall indicate only that the write flag is on.
108     *                  The file shall not be writable on a read-only file
109     *                  system even if this test indicates true.
110     *  -x file         True if file exists and is executable.
111     *                  True shall indicate only that the execute flag is on.
112     *                  If file is a directory, true indicates that the file
113     *                  can be searched.
114     */
115    if (mode != W_OK && mode != X_OK)
116        return access(name, mode);
117
118    if (stat(name, &statb) == -1)
119        return 1;
120
121    if (access(name, mode) == 0) {
122#ifdef S_ISDIR
123        if (S_ISDIR(statb.st_mode) && mode == X_OK)
124            return 0;
125#endif /* S_ISDIR */
126
127        /* root needs permission for someone */
128        switch (mode) {
129        case W_OK:
130            mode = S_IWUSR | S_IWGRP | S_IWOTH;
131            break;
132        case X_OK:
133            mode = S_IXUSR | S_IXGRP | S_IXOTH;
134            break;
135        default:
136            abort();
137            break;
138        }
139
140    }
141
142    else if (euid == statb.st_uid)
143        mode <<= 6;
144
145    else if (egid == statb.st_gid)
146        mode <<= 3;
147
148# ifdef NGROUPS_MAX
149    else {
150        /* you can be in several groups */
151        long    n;
152        GETGROUPS_T *groups;
153
154        /*
155         * Try these things to find a positive maximum groups value:
156         *   1) sysconf(_SC_NGROUPS_MAX)
157         *   2) NGROUPS_MAX
158         *   3) getgroups(0, unused)
159         * Then allocate and scan the groups array if one of these worked.
160         */
161#  if defined (HAVE_SYSCONF) && defined (_SC_NGROUPS_MAX)
162        if ((n = sysconf(_SC_NGROUPS_MAX)) == -1)
163#  endif /* _SC_NGROUPS_MAX */
164            n = NGROUPS_MAX;
165        if (n <= 0)
166            n = getgroups(0, (GETGROUPS_T *) NULL);
167
168        if (n > 0) {
169            groups = xmalloc((size_t) (n * sizeof(*groups)));
170            n = getgroups((int) n, groups);
171            while (--n >= 0)
172                if (groups[n] == statb.st_gid) {
173                    mode <<= 3;
174                    break;
175                }
176        }
177    }
178# endif /* NGROUPS_MAX */
179
180    if (statb.st_mode & mode)
181        return 0;
182    else
183        return 1;
184#endif /* !POSIX */
185}
186
187int
188expr(vp)
189    Char ***vp;
190{
191    return (exp0(vp, 0));
192}
193
194int
195exp0(vp, ignore)
196    Char ***vp;
197    int    ignore;
198{
199    int p1 = exp1(vp, ignore);
200
201#ifdef EDEBUG
202    etraci("exp0 p1", p1, vp);
203#endif /* EDEBUG */
204    if (**vp && eq(**vp, STRor2)) {
205        int p2;
206
207        (*vp)++;
208        p2 = exp0(vp, (ignore & TEXP_IGNORE) || p1);
209#ifdef EDEBUG
210        etraci("exp0 p2", p2, vp);
211#endif /* EDEBUG */
212        return (p1 || p2);
213    }
214    return (p1);
215}
216
217static int
218exp1(vp, ignore)
219    Char ***vp;
220    int    ignore;
221{
222    int p1 = exp2x(vp, ignore);
223
224#ifdef EDEBUG
225    etraci("exp1 p1", p1, vp);
226#endif /* EDEBUG */
227    if (**vp && eq(**vp, STRand2)) {
228        int p2;
229
230        (*vp)++;
231        p2 = exp1(vp, (ignore & TEXP_IGNORE) || !p1);
232#ifdef EDEBUG
233        etraci("exp1 p2", p2, vp);
234#endif /* EDEBUG */
235        return (p1 && p2);
236    }
237    return (p1);
238}
239
240static int
241exp2x(vp, ignore)
242    Char ***vp;
243    int    ignore;
244{
245    int p1 = exp2a(vp, ignore);
246
247#ifdef EDEBUG
248    etraci("exp3 p1", p1, vp);
249#endif /* EDEBUG */
250    if (**vp && eq(**vp, STRor)) {
251        int p2;
252
253        (*vp)++;
254        p2 = exp2x(vp, ignore);
255#ifdef EDEBUG
256        etraci("exp3 p2", p2, vp);
257#endif /* EDEBUG */
258        return (p1 | p2);
259    }
260    return (p1);
261}
262
263static int
264exp2a(vp, ignore)
265    Char ***vp;
266    int    ignore;
267{
268    int p1 = exp2b(vp, ignore);
269
270#ifdef EDEBUG
271    etraci("exp2a p1", p1, vp);
272#endif /* EDEBUG */
273    if (**vp && eq(**vp, STRcaret)) {
274        int p2;
275
276        (*vp)++;
277        p2 = exp2a(vp, ignore);
278#ifdef EDEBUG
279        etraci("exp2a p2", p2, vp);
280#endif /* EDEBUG */
281        return (p1 ^ p2);
282    }
283    return (p1);
284}
285
286static int
287exp2b(vp, ignore)
288    Char ***vp;
289    int    ignore;
290{
291    int p1 = exp2c(vp, ignore);
292
293#ifdef EDEBUG
294    etraci("exp2b p1", p1, vp);
295#endif /* EDEBUG */
296    if (**vp && eq(**vp, STRand)) {
297        int p2;
298
299        (*vp)++;
300        p2 = exp2b(vp, ignore);
301#ifdef EDEBUG
302        etraci("exp2b p2", p2, vp);
303#endif /* EDEBUG */
304        return (p1 & p2);
305    }
306    return (p1);
307}
308
309static int
310exp2c(vp, ignore)
311    Char ***vp;
312    int    ignore;
313{
314    Char *p1 = exp3(vp, ignore);
315    Char *p2;
316    int i;
317
318#ifdef EDEBUG
319    etracc("exp2c p1", p1, vp);
320#endif /* EDEBUG */
321    if ((i = isa(**vp, EQOP)) != 0) {
322        (*vp)++;
323        if (i == EQMATCH || i == NOTEQMATCH)
324            ignore |= TEXP_NOGLOB;
325        p2 = exp3(vp, ignore);
326#ifdef EDEBUG
327        etracc("exp2c p2", p2, vp);
328#endif /* EDEBUG */
329        if (!(ignore & TEXP_IGNORE))
330            switch (i) {
331
332            case EQEQ:
333                i = eq(p1, p2);
334                break;
335
336            case NOTEQ:
337                i = !eq(p1, p2);
338                break;
339
340            case EQMATCH:
341                i = Gmatch(p1, p2);
342                break;
343
344            case NOTEQMATCH:
345                i = !Gmatch(p1, p2);
346                break;
347            }
348        xfree((ptr_t) p1);
349        xfree((ptr_t) p2);
350        return (i);
351    }
352    i = egetn(p1);
353    xfree((ptr_t) p1);
354    return (i);
355}
356
357static Char *
358exp3(vp, ignore)
359    Char ***vp;
360    int    ignore;
361{
362    Char *p1, *p2;
363    int i;
364
365    p1 = exp3a(vp, ignore);
366#ifdef EDEBUG
367    etracc("exp3 p1", p1, vp);
368#endif /* EDEBUG */
369    if ((i = isa(**vp, RELOP)) != 0) {
370        (*vp)++;
371        if (**vp && eq(**vp, STRequal))
372            i |= 1, (*vp)++;
373        p2 = exp3(vp, ignore);
374#ifdef EDEBUG
375        etracc("exp3 p2", p2, vp);
376#endif /* EDEBUG */
377        if (!(ignore & TEXP_IGNORE))
378            switch (i) {
379
380            case GTR:
381                i = egetn(p1) > egetn(p2);
382                break;
383
384            case GTR | 1:
385                i = egetn(p1) >= egetn(p2);
386                break;
387
388            case LSS:
389                i = egetn(p1) < egetn(p2);
390                break;
391
392            case LSS | 1:
393                i = egetn(p1) <= egetn(p2);
394                break;
395            }
396        xfree((ptr_t) p1);
397        xfree((ptr_t) p2);
398        return (putn(i));
399    }
400    return (p1);
401}
402
403static Char *
404exp3a(vp, ignore)
405    Char ***vp;
406    int    ignore;
407{
408    Char *p1, *p2, *op;
409    int i;
410
411    p1 = exp4(vp, ignore);
412#ifdef EDEBUG
413    etracc("exp3a p1", p1, vp);
414#endif /* EDEBUG */
415    op = **vp;
416    if (op && any("<>", op[0]) && op[0] == op[1]) {
417        (*vp)++;
418        p2 = exp3a(vp, ignore);
419#ifdef EDEBUG
420        etracc("exp3a p2", p2, vp);
421#endif /* EDEBUG */
422        if (op[0] == '<')
423            i = egetn(p1) << egetn(p2);
424        else
425            i = egetn(p1) >> egetn(p2);
426        xfree((ptr_t) p1);
427        xfree((ptr_t) p2);
428        return (putn(i));
429    }
430    return (p1);
431}
432
433static Char *
434exp4(vp, ignore)
435    Char ***vp;
436    int    ignore;
437{
438    Char *p1, *p2;
439    int i = 0;
440
441    p1 = exp5(vp, ignore);
442#ifdef EDEBUG
443    etracc("exp4 p1", p1, vp);
444#endif /* EDEBUG */
445    if (isa(**vp, ADDOP)) {
446        Char *op = *(*vp)++;
447
448        p2 = exp4(vp, ignore);
449#ifdef EDEBUG
450        etracc("exp4 p2", p2, vp);
451#endif /* EDEBUG */
452        if (!(ignore & TEXP_IGNORE))
453            switch (op[0]) {
454
455            case '+':
456                i = egetn(p1) + egetn(p2);
457                break;
458
459            case '-':
460                i = egetn(p1) - egetn(p2);
461                break;
462            }
463        xfree((ptr_t) p1);
464        xfree((ptr_t) p2);
465        return (putn(i));
466    }
467    return (p1);
468}
469
470static Char *
471exp5(vp, ignore)
472    Char ***vp;
473    int    ignore;
474{
475    Char *p1, *p2;
476    int i = 0;
477
478    p1 = exp6(vp, ignore);
479#ifdef EDEBUG
480    etracc("exp5 p1", p1, vp);
481#endif /* EDEBUG */
482
483    if (isa(**vp, MULOP)) {
484        Char *op = *(*vp)++;
485        if ((ignore & TEXP_NOGLOB) != 0)
486            /*
487             * We are just trying to get the right side of
488             * a =~ or !~ operator
489             */
490            return Strsave(op);
491
492        p2 = exp5(vp, ignore);
493#ifdef EDEBUG
494        etracc("exp5 p2", p2, vp);
495#endif /* EDEBUG */
496        if (!(ignore & TEXP_IGNORE))
497            switch (op[0]) {
498
499            case '*':
500                i = egetn(p1) * egetn(p2);
501                break;
502
503            case '/':
504                i = egetn(p2);
505                if (i == 0)
506                    stderror(ERR_DIV0);
507                i = egetn(p1) / i;
508                break;
509
510            case '%':
511                i = egetn(p2);
512                if (i == 0)
513                    stderror(ERR_MOD0);
514                i = egetn(p1) % i;
515                break;
516            }
517        xfree((ptr_t) p1);
518        xfree((ptr_t) p2);
519        return (putn(i));
520    }
521    return (p1);
522}
523
524static Char *
525exp6(vp, ignore)
526    Char ***vp;
527    int    ignore;
528{
529    int     ccode, i = 0;
530    Char *cp;
531
532    if (**vp == 0)
533        stderror(ERR_NAME | ERR_EXPRESSION);
534    if (eq(**vp, STRbang)) {
535        (*vp)++;
536        cp = exp6(vp, ignore);
537#ifdef EDEBUG
538        etracc("exp6 ! cp", cp, vp);
539#endif /* EDEBUG */
540        i = egetn(cp);
541        xfree((ptr_t) cp);
542        return (putn(!i));
543    }
544    if (eq(**vp, STRtilde)) {
545        (*vp)++;
546        cp = exp6(vp, ignore);
547#ifdef EDEBUG
548        etracc("exp6 ~ cp", cp, vp);
549#endif /* EDEBUG */
550        i = egetn(cp);
551        xfree((ptr_t) cp);
552        return (putn(~i));
553    }
554    if (eq(**vp, STRLparen)) {
555        (*vp)++;
556        ccode = exp0(vp, ignore);
557#ifdef EDEBUG
558        etraci("exp6 () ccode", ccode, vp);
559#endif /* EDEBUG */
560        if (*vp == 0 || **vp == 0 || ***vp != ')')
561            stderror(ERR_NAME | ERR_EXPRESSION);
562        (*vp)++;
563        return (putn(ccode));
564    }
565    if (eq(**vp, STRLbrace)) {
566        Char **v;
567        struct command faket;
568        Char   *fakecom[2];
569
570        faket.t_dtyp = NODE_COMMAND;
571        faket.t_dflg = F_BACKQ;
572        faket.t_dcar = faket.t_dcdr = faket.t_dspr = NULL;
573        faket.t_dcom = fakecom;
574        fakecom[0] = STRfakecom;
575        fakecom[1] = NULL;
576        (*vp)++;
577        v = *vp;
578        for (;;) {
579            if (!**vp)
580                stderror(ERR_NAME | ERR_MISSING, '}');
581            if (eq(*(*vp)++, STRRbrace))
582                break;
583        }
584        if (ignore & TEXP_IGNORE)
585            return (Strsave(STRNULL));
586        psavejob();
587        if (pfork(&faket, -1) == 0) {
588            *--(*vp) = 0;
589            evalav(v);
590            exitstat();
591        }
592        pwait();
593        prestjob();
594#ifdef EDEBUG
595        etraci("exp6 {} status", egetn(varval(STRstatus)), vp);
596#endif /* EDEBUG */
597        return (putn(egetn(varval(STRstatus)) == 0));
598    }
599    if (isa(**vp, ANYOP))
600        return (Strsave(STRNULL));
601    cp = *(*vp)++;
602#ifdef convex
603# define FILETESTS "erwxfdzoplstSXLbcugkmKR"
604#else
605# define FILETESTS "erwxfdzoplstSXLbcugkmK"
606#endif /* convex */
607#define FILEVALS  "ZAMCDIUGNFPL"
608    if (*cp == '-' && (any(FILETESTS, cp[1]) || any(FILEVALS, cp[1])))
609        return(filetest(cp, vp, ignore));
610#ifdef EDEBUG
611    etracc("exp6 default", cp, vp);
612#endif /* EDEBUG */
613    return (ignore & TEXP_NOGLOB ? Strsave(cp) : globone(cp, G_APPEND));
614}
615
616
617/*
618 * Extended file tests
619 * From: John Rowe <rowe@excc.exeter.ac.uk>
620 */
621Char *
622filetest(cp, vp, ignore)
623    Char *cp, ***vp;
624    int ignore;
625{
626#ifdef convex
627    struct cvxstat stb, *st = NULL;
628# define TCSH_STAT      stat64
629#else
630# define TCSH_STAT      stat
631    struct stat stb, *st = NULL;
632#endif /* convex */
633
634#ifdef S_IFLNK
635# ifdef convex
636    struct cvxstat lstb, *lst = NULL;
637#  define TCSH_LSTAT lstat64
638# else
639#  define TCSH_LSTAT lstat
640    struct stat lstb, *lst = NULL;
641# endif /* convex */
642    char *filnam;
643#endif /* S_IFLNK */
644
645    int i = 0;
646    unsigned pmask = 0xffff;
647    int altout = 0;
648    Char *ft = cp, *dp, *ep, *strdev, *strino, *strF, *str, valtest = '\0',
649    *errval = STR0;
650    char *string, string0[8];
651    time_t footime;
652    struct passwd *pw;
653    struct group *gr;
654
655    while(any(FILETESTS, *++ft))
656        continue;
657
658    if (!*ft && *(ft - 1) == 'L')
659        --ft;
660
661    if (any(FILEVALS, *ft)) {
662        valtest = *ft++;
663        /*
664         * Value tests return '-1' on failure as 0 is
665         * a legitimate value for many of them.
666         * 'F' returns ':' for compatibility.
667         */
668        errval = valtest == 'F' ? STRcolon : STRminus1;
669
670        if (valtest == 'P' && *ft >= '0' && *ft <= '7') {
671            pmask = (char) *ft - '0';
672            while ( *++ft >= '0' && *ft <= '7' )
673                pmask = 8 * pmask + ((char) *ft - '0');
674        }
675        if (Strcmp(ft, STRcolon) == 0 && any("AMCUGP", valtest)) {
676            altout = 1;
677            ++ft;
678        }
679    }
680
681    if (*ft || ft == cp + 1)
682        stderror(ERR_NAME | ERR_FILEINQ);
683
684    /*
685     * Detect missing file names by checking for operator in the file name
686     * position.  However, if an operator name appears there, we must make
687     * sure that there's no file by that name (e.g., "/") before announcing
688     * an error.  Even this check isn't quite right, since it doesn't take
689     * globbing into account.
690     */
691
692    if (isa(**vp, ANYOP) && TCSH_STAT(short2str(**vp), &stb))
693        stderror(ERR_NAME | ERR_FILENAME);
694
695    dp = *(*vp)++;
696    if (ignore & TEXP_IGNORE)
697        return (Strsave(STRNULL));
698    ep = globone(dp, G_APPEND);
699    ft = &cp[1];
700    do
701        switch (*ft) {
702
703        case 'r':
704            i = !sh_access(ep, R_OK);
705            break;
706
707        case 'w':
708            i = !sh_access(ep, W_OK);
709            break;
710
711        case 'x':
712            i = !sh_access(ep, X_OK);
713            break;
714
715        case 'X':       /* tcsh extension, name is an executable in the path
716                         * or a tcsh builtin command
717                         */
718            i = find_cmd(ep, 0);
719            break;
720
721        case 't':       /* SGI extension, true when file is a tty */
722            i = isatty(atoi(short2str(ep)));
723            break;
724
725        default:
726
727#ifdef S_IFLNK
728            if (tolower(*ft) == 'l') {
729                /*
730                 * avoid convex compiler bug.
731                 */
732                if (!lst) {
733                    lst = &lstb;
734                    if (TCSH_LSTAT(short2str(ep), lst) == -1) {
735                        xfree((ptr_t) ep);
736                        return (Strsave(errval));
737                    }
738                }
739                if (*ft == 'L')
740                    st = lst;
741            }
742            else
743#endif /* S_IFLNK */
744                /*
745                 * avoid convex compiler bug.
746                 */
747                if (!st) {
748                    st = &stb;
749                    if (TCSH_STAT(short2str(ep), st) == -1) {
750                        xfree((ptr_t) ep);
751                        return (Strsave(errval));
752                    }
753                }
754
755            switch (*ft) {
756
757            case 'f':
758#ifdef S_ISREG
759                i = S_ISREG(st->st_mode);
760#else /* !S_ISREG */
761                i = 0;
762#endif /* S_ISREG */
763                break;
764
765            case 'd':
766#ifdef S_ISDIR
767                i = S_ISDIR(st->st_mode);
768#else /* !S_ISDIR */
769                i = 0;
770#endif /* S_ISDIR */
771                break;
772
773            case 'p':
774#ifdef S_ISFIFO
775                i = S_ISFIFO(st->st_mode);
776#else /* !S_ISFIFO */
777                i = 0;
778#endif /* S_ISFIFO */
779                break;
780
781            case 'm' :
782#ifdef S_ISOFL
783              i = S_ISOFL(st->st_dm_mode);
784#else /* !S_ISOFL */
785              i = 0;
786#endif /* S_ISOFL */
787              break ;
788
789            case 'K' :
790#ifdef S_ISOFL
791              i = stb.st_dm_key;
792#else /* !S_ISOFL */
793              i = 0;
794#endif /* S_ISOFL */
795              break ;
796 
797
798            case 'l':
799#ifdef S_ISLNK
800                i = S_ISLNK(lst->st_mode);
801#else /* !S_ISLNK */
802                i = 0;
803#endif /* S_ISLNK */
804                break;
805
806            case 'S':
807# ifdef S_ISSOCK
808                i = S_ISSOCK(st->st_mode);
809# else /* !S_ISSOCK */
810                i = 0;
811# endif /* S_ISSOCK */
812                break;
813
814            case 'b':
815#ifdef S_ISBLK
816                i = S_ISBLK(st->st_mode);
817#else /* !S_ISBLK */
818                i = 0;
819#endif /* S_ISBLK */
820                break;
821
822            case 'c':
823#ifdef S_ISCHR
824                i = S_ISCHR(st->st_mode);
825#else /* !S_ISCHR */
826                i = 0;
827#endif /* S_ISCHR */
828                break;
829
830            case 'u':
831                i = (S_ISUID & st->st_mode) != 0;
832                break;
833
834            case 'g':
835                i = (S_ISGID & st->st_mode) != 0;
836                break;
837
838            case 'k':
839                i = (S_ISVTX & st->st_mode) != 0;
840                break;
841
842            case 'z':
843                i = st->st_size == 0;
844                break;
845
846#ifdef convex
847            case 'R':
848                i = (stb.st_dmonflags & IMIGRATED) == IMIGRATED;
849                break;
850#endif /* convex */
851
852            case 's':
853                i = stb.st_size != 0;
854                break;
855
856            case 'e':
857                i = 1;
858                break;
859
860            case 'o':
861                i = st->st_uid == uid;
862                break;
863
864                /*
865                 * Value operators are a tcsh extension.
866                 */
867
868            case 'D':
869                i = (int) st->st_dev;
870                break;
871
872            case 'I':
873                i = (int) st->st_ino;
874                break;
875               
876            case 'F':
877                strdev = putn( (int) st->st_dev);
878                strino = putn( (int) st->st_ino);
879                strF = (Char *) xmalloc((size_t) (2 + Strlen(strdev) +
880                                         Strlen(strino)) * sizeof(Char));
881                (void) Strcat(Strcat(Strcpy(strF, strdev), STRcolon), strino);
882                xfree((ptr_t) strdev);
883                xfree((ptr_t) strino);
884                xfree((ptr_t) ep);
885                return(strF);
886               
887            case 'L':
888                if ( *(ft + 1) ) {
889                    i = 1;
890                    break;
891                }
892#ifdef S_ISLNK
893                filnam = short2str(ep);
894#ifdef PATH_MAX
895# define MY_PATH_MAX PATH_MAX
896#else /* !PATH_MAX */
897/*
898 * I can't think of any more sensible alterative; readlink doesn't give
899 * us an errno if the buffer isn't large enough :-(
900 */
901# define MY_PATH_MAX  2048
902#endif /* PATH_MAX */
903                i = readlink(filnam, string = (char *)
904                      xmalloc((size_t) (1 + MY_PATH_MAX) * sizeof(char)),
905                        MY_PATH_MAX);
906                if (i >= 0 && i <= MY_PATH_MAX)
907                    string[i] = '\0'; /* readlink does not null terminate */
908                strF = (i < 0) ? errval : str2short(string);
909                xfree((ptr_t) string);
910                xfree((ptr_t) ep);
911                return(Strsave(strF));
912
913#else /* !S_ISLNK */
914                i = 0;
915                break;
916#endif /* S_ISLNK */
917               
918
919            case 'N':
920                i = (int) st->st_nlink;
921                break;
922
923            case 'P':
924                string = string0 + 1;
925                (void) xsnprintf(string, sizeof(string0) - 1, "%o",
926                    pmask & (unsigned int)
927                    ((S_IRWXU|S_IRWXG|S_IRWXO|S_ISUID|S_ISGID) & st->st_mode));
928                if (altout && *string != '0')
929                    *--string = '0';
930                xfree((ptr_t) ep);
931                return(Strsave(str2short(string)));
932
933            case 'U':
934                if (altout && (pw = getpwuid(st->st_uid))) {
935                    xfree((ptr_t) ep);
936                    return(Strsave(str2short(pw->pw_name)));
937                }
938                i = (int) st->st_uid;
939                break;
940
941            case 'G':
942                if ( altout && (gr = getgrgid(st->st_gid))) {
943                    xfree((ptr_t) ep);
944                    return(Strsave(str2short(gr->gr_name)));
945                }
946                i = (int) st->st_gid;
947                break;
948
949            case 'Z':
950                i = (int) st->st_size;
951                break;
952
953            case 'A': case 'M': case 'C':
954                footime = *ft == 'A' ? st->st_atime :
955                    *ft == 'M' ? st->st_mtime : st->st_ctime;
956                if (altout) {
957                    strF = str2short(ctime(&footime));
958                    if ((str = Strchr(strF, '\n')) != NULL)
959                        *str = (Char) '\0';
960                    xfree((ptr_t) ep);
961                    return(Strsave(strF));
962                }
963                i = (int) footime;
964                break;
965
966            }
967        }
968    while (*++ft && i);
969#ifdef EDEBUG
970    etraci("exp6 -? i", i, vp);
971#endif /* EDEBUG */
972    xfree((ptr_t) ep);
973    return (putn(i));
974}
975
976
977static void
978evalav(v)
979    Char **v;
980{
981    struct wordent paraml1;
982    struct wordent *hp = &paraml1;
983    struct command *t;
984    struct wordent *wdp = hp;
985
986    set(STRstatus, Strsave(STR0), VAR_READWRITE);
987    hp->prev = hp->next = hp;
988    hp->word = STRNULL;
989    while (*v) {
990        struct wordent *new =
991        (struct wordent *) xcalloc(1, sizeof *wdp);
992
993        new->prev = wdp;
994        new->next = hp;
995        wdp->next = new;
996        wdp = new;
997        wdp->word = Strsave(*v++);
998    }
999    hp->prev = wdp;
1000    alias(&paraml1);
1001    t = syntax(paraml1.next, &paraml1, 0);
1002    if (seterr)
1003        stderror(ERR_OLD);
1004    execute(t, -1, NULL, NULL, TRUE);
1005    freelex(&paraml1), freesyn(t);
1006}
1007
1008static int
1009isa(cp, what)
1010    Char *cp;
1011    int what;
1012{
1013    if (cp == 0)
1014        return ((what & RESTOP) != 0);
1015    if (*cp == '\0')
1016        return 0;
1017    if (cp[1] == 0) {
1018        if (what & ADDOP && (*cp == '+' || *cp == '-'))
1019            return (1);
1020        if (what & MULOP && (*cp == '*' || *cp == '/' || *cp == '%'))
1021            return (1);
1022        if (what & RESTOP && (*cp == '(' || *cp == ')' || *cp == '!' ||
1023                              *cp == '~' || *cp == '^' || *cp == '"'))
1024            return (1);
1025    }
1026    else if (cp[2] == 0) {
1027        if (what & RESTOP) {
1028            if (cp[0] == '|' && cp[1] == '&')
1029                return (1);
1030            if (cp[0] == '<' && cp[1] == '<')
1031                return (1);
1032            if (cp[0] == '>' && cp[1] == '>')
1033                return (1);
1034        }
1035        if (what & EQOP) {
1036            if (cp[0] == '=') {
1037                if (cp[1] == '=')
1038                    return (EQEQ);
1039                if (cp[1] == '~')
1040                    return (EQMATCH);
1041            }
1042            else if (cp[0] == '!') {
1043                if (cp[1] == '=')
1044                    return (NOTEQ);
1045                if (cp[1] == '~')
1046                    return (NOTEQMATCH);
1047            }
1048        }
1049    }
1050    if (what & RELOP) {
1051        if (*cp == '<')
1052            return (LSS);
1053        if (*cp == '>')
1054            return (GTR);
1055    }
1056    return (0);
1057}
1058
1059static int
1060egetn(cp)
1061    Char *cp;
1062{
1063    if (*cp && *cp != '-' && !Isdigit(*cp))
1064        stderror(ERR_NAME | ERR_EXPRESSION);
1065    return (getn(cp));
1066}
1067
1068/* Phew! */
1069
1070#ifdef EDEBUG
1071static void
1072etraci(str, i, vp)
1073    char   *str;
1074    int     i;
1075    Char ***vp;
1076{
1077    xprintf("%s=%d\t", str, i);
1078    blkpr(*vp);
1079    xputchar('\n');
1080}
1081static void
1082etracc(str, cp, vp)
1083    char   *str;
1084    Char   *cp;
1085    Char ***vp;
1086{
1087    xprintf("%s=%s\t", str, cp);
1088    blkpr(*vp);
1089    xputchar('\n');
1090}
1091#endif /* EDEBUG */
Note: See TracBrowser for help on using the repository browser.