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

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