1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-09-03 10:21:46 +02:00
zsh/Src/cond.c
1999-10-18 12:09:40 +00:00

403 lines
8.9 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 && c->type != COND_STREQ && c->type != COND_STRNEQ) {
right = dupstring((char *) c->right);
singsub(&right);
untokenize(right);
}
if (tracingcond) {
if (c->type < COND_MOD) {
char *rt = (char *) right;
if (c->type == COND_STREQ || c->type == COND_STRNEQ) {
rt = dupstring(c->right);
singsub(&rt);
untokenize(rt);
}
fprintf(stderr, " %s %s %s", (char *)left, condstr[c->type],
rt);
} else
fprintf(stderr, " -%c %s", c->type, (char *)left);
}
if (c->type >= COND_EQ && c->type <= COND_GE) {
mnumber mn1, mn2;
mn1 = matheval(left);
mn2 = matheval(right);
if (((mn1.type|mn2.type) & (MN_INTEGER|MN_FLOAT)) ==
(MN_INTEGER|MN_FLOAT)) {
/* promote to float */
if (mn1.type & MN_INTEGER) {
mn1.type = MN_FLOAT;
mn1.u.d = (double)mn1.u.l;
}
if (mn2.type & MN_INTEGER) {
mn2.type = MN_FLOAT;
mn2.u.d = (double)mn2.u.l;
}
}
switch(c->type) {
case COND_EQ:
return (mn1.type & MN_FLOAT) ? (mn1.u.d == mn2.u.d) :
(mn1.u.l == mn2.u.l);
case COND_NE:
return (mn1.type & MN_FLOAT) ? (mn1.u.d != mn2.u.d) :
(mn1.u.l != mn2.u.l);
case COND_LT:
return (mn1.type & MN_FLOAT) ? (mn1.u.d < mn2.u.d) :
(mn1.u.l < mn2.u.l);
case COND_GT:
return (mn1.type & MN_FLOAT) ? (mn1.u.d > mn2.u.d) :
(mn1.u.l > mn2.u.l);
case COND_LE:
return (mn1.type & MN_FLOAT) ? (mn1.u.d <= mn2.u.d) :
(mn1.u.l <= mn2.u.l);
case COND_GE:
return (mn1.type & MN_FLOAT) ? (mn1.u.d >= mn2.u.d) :
(mn1.u.l >= mn2.u.l);
}
}
switch (c->type) {
case COND_STREQ:
case COND_STRNEQ:
{
Patprog pprog = c->prog;
int test;
if (pprog == dummy_patprog1 || pprog == dummy_patprog2) {
char *opat;
int save;
right = opat = dupstring((char *) c->right);
singsub(&right);
save = (!strcmp(opat, right) && pprog != dummy_patprog2);
if (!(pprog = patcompile(right, (save ? PAT_ZDUP : PAT_STATIC),
NULL)))
zerr("bad pattern: %s", right, 0);
else if (save)
c->prog = pprog;
}
test = (pprog && pattry(pprog, left));
return (c->type == COND_STREQ ? test : !test);
}
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(mathevali(left));
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 mathevali(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++);
}
}