mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-09-03 10:21:46 +02:00
356 lines
7.7 KiB
C
356 lines
7.7 KiB
C
/*
|
|
* cond.c - evaluate conditional expressions
|
|
*
|
|
* This file is part of zsh, the Z shell.
|
|
*
|
|
* Copyright (c) 1992-1997 Paul Falstad
|
|
* All rights reserved.
|
|
*
|
|
* Permission is hereby granted, without written agreement and without
|
|
* license or royalty fees, to use, copy, modify, and distribute this
|
|
* software and to distribute modified versions of this software for any
|
|
* purpose, provided that the above copyright notice and the following
|
|
* two paragraphs appear in all copies of this software.
|
|
*
|
|
* In no event shall Paul Falstad or the Zsh Development Group be liable
|
|
* to any party for direct, indirect, special, incidental, or consequential
|
|
* damages arising out of the use of this software and its documentation,
|
|
* even if Paul Falstad and the Zsh Development Group have been advised of
|
|
* the possibility of such damage.
|
|
*
|
|
* Paul Falstad and the Zsh Development Group specifically disclaim any
|
|
* warranties, including, but not limited to, the implied warranties of
|
|
* merchantability and fitness for a particular purpose. The software
|
|
* provided hereunder is on an "as is" basis, and Paul Falstad and the
|
|
* Zsh Development Group have no obligation to provide maintenance,
|
|
* support, updates, enhancements, or modifications.
|
|
*
|
|
*/
|
|
|
|
#include "zsh.mdh"
|
|
#include "cond.pro"
|
|
|
|
int tracingcond;
|
|
|
|
static char *condstr[COND_MOD] = {
|
|
"!", "&&", "||", "==", "!=", "<", ">", "-nt", "-ot", "-ef", "-eq",
|
|
"-ne", "-lt", "-gt", "-le", "-ge"
|
|
};
|
|
|
|
/**/
|
|
int
|
|
evalcond(Cond c)
|
|
{
|
|
struct stat *st;
|
|
char *left, *right = NULL;
|
|
|
|
switch (c->type) {
|
|
case COND_NOT:
|
|
if (tracingcond)
|
|
fprintf(stderr, " %s", condstr[c->type]);
|
|
return !evalcond(c->left);
|
|
case COND_AND:
|
|
if (evalcond(c->left)) {
|
|
if (tracingcond)
|
|
fprintf(stderr, " %s", condstr[c->type]);
|
|
return evalcond(c->right);
|
|
} else
|
|
return 0;
|
|
case COND_OR:
|
|
if (!evalcond(c->left)) {
|
|
if (tracingcond)
|
|
fprintf(stderr, " %s", condstr[c->type]);
|
|
return evalcond(c->right);
|
|
} else
|
|
return 1;
|
|
case COND_MOD:
|
|
case COND_MODI:
|
|
{
|
|
Conddef cd;
|
|
|
|
if ((cd = getconddef((c->type == COND_MODI),
|
|
((char *) c->left) + 1, 1))) {
|
|
if (c->type == COND_MOD) {
|
|
int l = arrlen((char **) c->right);
|
|
|
|
if (l < cd->min || (cd->max >= 0 && l > cd->max)) {
|
|
zerr("unrecognized condition: `%s'", (char *) c->left, 0);
|
|
return 0;
|
|
}
|
|
}
|
|
if (tracingcond)
|
|
tracemodcond((char *)c->left, (char **)c->right,
|
|
c->type == COND_MODI);
|
|
return cd->handler((char **) c->right, cd->condid);
|
|
}
|
|
else {
|
|
char **a = (char **) c->right, *s = a[0];
|
|
|
|
if (s && s[0] == '-' &&
|
|
(cd = getconddef(0, s + 1, 1))) {
|
|
int l = arrlen(a);
|
|
|
|
if (l < cd->min || (cd->max >= 0 && l > cd->max)) {
|
|
zerr("unrecognized condition: `%s'", (char *) c->left, 0);
|
|
return 0;
|
|
}
|
|
if (tracingcond)
|
|
tracemodcond((char *)c->left, a, c->type == COND_MODI);
|
|
a[0] = (char *) c->left;
|
|
return cd->handler(a, cd->condid);
|
|
} else
|
|
zerr("unrecognized condition: `%s'", (char *) c->left, 0);
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
left = dupstring((char *) c->left);
|
|
singsub(&left);
|
|
untokenize(left);
|
|
if (c->right) {
|
|
right = dupstring((char *) c->right);
|
|
singsub(&right);
|
|
if (c->type != COND_STREQ && c->type != COND_STRNEQ)
|
|
untokenize(right);
|
|
}
|
|
|
|
if (tracingcond) {
|
|
if (c->type < COND_MOD) {
|
|
char *rt = (char *)right;
|
|
if (c->type == COND_STREQ || c->type == COND_STRNEQ) {
|
|
rt = dupstring(rt);
|
|
untokenize(rt);
|
|
}
|
|
fprintf(stderr, " %s %s %s", (char *)left, condstr[c->type],
|
|
rt);
|
|
} else
|
|
fprintf(stderr, " -%c %s", c->type, (char *)left);
|
|
}
|
|
|
|
switch (c->type) {
|
|
case COND_STREQ:
|
|
return matchpat(left, right);
|
|
case COND_STRNEQ:
|
|
return !matchpat(left, right);
|
|
case COND_STRLT:
|
|
return strcmp(left, right) < 0;
|
|
case COND_STRGTR:
|
|
return strcmp(left, right) > 0;
|
|
case 'e':
|
|
case 'a':
|
|
return (doaccess(left, F_OK));
|
|
case 'b':
|
|
return (S_ISBLK(dostat(left)));
|
|
case 'c':
|
|
return (S_ISCHR(dostat(left)));
|
|
case 'd':
|
|
return (S_ISDIR(dostat(left)));
|
|
case 'f':
|
|
return (S_ISREG(dostat(left)));
|
|
case 'g':
|
|
return (!!(dostat(left) & S_ISGID));
|
|
case 'k':
|
|
return (!!(dostat(left) & S_ISVTX));
|
|
case 'n':
|
|
return (!!strlen(left));
|
|
case 'o':
|
|
return (optison(left));
|
|
case 'p':
|
|
return (S_ISFIFO(dostat(left)));
|
|
case 'r':
|
|
return (doaccess(left, R_OK));
|
|
case 's':
|
|
return ((st = getstat(left)) && !!(st->st_size));
|
|
case 'S':
|
|
return (S_ISSOCK(dostat(left)));
|
|
case 'u':
|
|
return (!!(dostat(left) & S_ISUID));
|
|
case 'w':
|
|
return (doaccess(left, W_OK));
|
|
case 'x':
|
|
if (privasserted()) {
|
|
mode_t mode = dostat(left);
|
|
return (mode & S_IXUGO) || S_ISDIR(mode);
|
|
}
|
|
return doaccess(left, X_OK);
|
|
case 'z':
|
|
return (!strlen(left));
|
|
case 'h':
|
|
case 'L':
|
|
return (S_ISLNK(dolstat(left)));
|
|
case 'O':
|
|
return ((st = getstat(left)) && st->st_uid == geteuid());
|
|
case 'G':
|
|
return ((st = getstat(left)) && st->st_gid == getegid());
|
|
case 'N':
|
|
return ((st = getstat(left)) && st->st_atime <= st->st_mtime);
|
|
case 't':
|
|
return isatty(matheval(left));
|
|
case COND_EQ:
|
|
return matheval(left) == matheval(right);
|
|
case COND_NE:
|
|
return matheval(left) != matheval(right);
|
|
case COND_LT:
|
|
return matheval(left) < matheval(right);
|
|
case COND_GT:
|
|
return matheval(left) > matheval(right);
|
|
case COND_LE:
|
|
return matheval(left) <= matheval(right);
|
|
case COND_GE:
|
|
return matheval(left) >= matheval(right);
|
|
case COND_NT:
|
|
case COND_OT:
|
|
{
|
|
time_t a;
|
|
|
|
if (!(st = getstat(left)))
|
|
return 0;
|
|
a = st->st_mtime;
|
|
if (!(st = getstat(right)))
|
|
return 0;
|
|
return (c->type == COND_NT) ? a > st->st_mtime : a < st->st_mtime;
|
|
}
|
|
case COND_EF:
|
|
{
|
|
dev_t d;
|
|
ino_t i;
|
|
|
|
if (!(st = getstat(left)))
|
|
return 0;
|
|
d = st->st_dev;
|
|
i = st->st_ino;
|
|
if (!(st = getstat(right)))
|
|
return 0;
|
|
return d == st->st_dev && i == st->st_ino;
|
|
}
|
|
default:
|
|
zerr("bad cond structure", NULL, 0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**/
|
|
static int
|
|
doaccess(char *s, int c)
|
|
{
|
|
return !access(unmeta(s), c);
|
|
}
|
|
|
|
|
|
static struct stat st;
|
|
|
|
/**/
|
|
static struct stat *
|
|
getstat(char *s)
|
|
{
|
|
/* /dev/fd/n refers to the open file descriptor n. We always use fstat *
|
|
* in this case since on Solaris /dev/fd/n is a device special file */
|
|
if (!strncmp(s, "/dev/fd/", 8)) {
|
|
if (fstat(atoi(s + 8), &st))
|
|
return NULL;
|
|
return &st;
|
|
}
|
|
|
|
if (stat(unmeta(s), &st))
|
|
return NULL;
|
|
return &st;
|
|
}
|
|
|
|
|
|
/**/
|
|
static mode_t
|
|
dostat(char *s)
|
|
{
|
|
struct stat *statp;
|
|
|
|
if (!(statp = getstat(s)))
|
|
return 0;
|
|
return statp->st_mode;
|
|
}
|
|
|
|
|
|
/* pem@aaii.oz; needed since dostat now uses "stat" */
|
|
|
|
/**/
|
|
static mode_t
|
|
dolstat(char *s)
|
|
{
|
|
if (lstat(unmeta(s), &st) < 0)
|
|
return 0;
|
|
return st.st_mode;
|
|
}
|
|
|
|
|
|
/**/
|
|
static int
|
|
optison(char *s)
|
|
{
|
|
int i;
|
|
|
|
if (strlen(s) == 1)
|
|
i = optlookupc(*s);
|
|
else
|
|
i = optlookup(s);
|
|
if (!i) {
|
|
zerr("no such option: %s", s, 0);
|
|
return 0;
|
|
} else if(i < 0)
|
|
return unset(-i);
|
|
else
|
|
return isset(i);
|
|
}
|
|
|
|
/**/
|
|
char *
|
|
cond_str(char **args, int num, int raw)
|
|
{
|
|
char *s = args[num];
|
|
|
|
singsub(&s);
|
|
if (!raw)
|
|
untokenize(s);
|
|
|
|
return s;
|
|
}
|
|
|
|
/**/
|
|
zlong
|
|
cond_val(char **args, int num)
|
|
{
|
|
char *s = args[num];
|
|
|
|
singsub(&s);
|
|
untokenize(s);
|
|
|
|
return matheval(s);
|
|
}
|
|
|
|
/**/
|
|
int
|
|
cond_match(char **args, int num, char *str)
|
|
{
|
|
char *s = args[num];
|
|
|
|
singsub(&s);
|
|
|
|
return matchpat(str, s);
|
|
}
|
|
|
|
/**/
|
|
static void
|
|
tracemodcond(char *name, char **args, int inf)
|
|
{
|
|
char **aptr;
|
|
MUSTUSEHEAP("tracemodcond");
|
|
args = duparray(args, (VFunc) dupstring);
|
|
for (aptr = args; *aptr; aptr++)
|
|
untokenize(*aptr);
|
|
if (inf) {
|
|
fprintf(stderr, " %s %s %s", args[0], name, args[1]);
|
|
} else {
|
|
fprintf(stderr, " %s", name);
|
|
while (*args)
|
|
fprintf(stderr, " %s", *args++);
|
|
}
|
|
}
|