
/*
 *
 * cond.c - evaluate conditional expressions
 *
 * This file is part of zsh, the Z shell.
 *
 * This software is Copyright 1992 by Paul Falstad
 *
 * Permission is hereby granted to copy, reproduce, redistribute or otherwise
 * use this software as long as: there is no monetary profit gained
 * specifically from the use or reproduction of this software, it is not
 * sold, rented, traded or otherwise marketed, and this copyright notice is
 * included prominently in any copy made.
 *
 * The author make no claims as to the fitness or correctness of this software
 * for any use whatsoever, and it is provided as is. Any use of this software
 * is at the user's own risk.
 *
 */

#include "zsh.h"

int evalcond(c)			/**/
Cond c;
{
    struct stat *st;

    switch (c->type) {
    case COND_NOT:
	return !evalcond(c->left);
    case COND_AND:
	return evalcond(c->left) && evalcond(c->right);
    case COND_OR:
	return evalcond(c->left) || evalcond(c->right);
    }
    singsub((char **)&c->left);
    untokenize(c->left);
    if (c->right) {
	singsub((char **)&c->right);
	if (c->type != COND_STREQ && c->type != COND_STRNEQ)
	    untokenize(c->right);
    }
    switch (c->type) {
    case COND_STREQ:
	return matchpat(c->left, c->right);
    case COND_STRNEQ:
	return !matchpat(c->left, c->right);
    case COND_STRLT:
	return strcmp(c->left, c->right) < 0;
    case COND_STRGTR:
	return strcmp(c->left, c->right) > 0;
    case 'e':
    case 'a':
	return (doaccess(c->left, F_OK));
    case 'b':
	return (S_ISBLK(dostat(c->left)));
    case 'c':
	return (S_ISCHR(dostat(c->left)));
    case 'd':
	return (S_ISDIR(dostat(c->left)));
    case 'f':
	return (S_ISREG(dostat(c->left)));
    case 'g':
	return (!!(dostat(c->left) & S_ISGID));
    case 'k':
	return (!!(dostat(c->left) & S_ISVTX));
    case 'n':
	return (!!strlen(c->left));
    case 'o':
	return (optison(c->left));
    case 'p':
	return (S_ISFIFO(dostat(c->left)));
    case 'r':
	return (doaccess(c->left, R_OK));
    case 's':
	return ((st = getstat(c->left)) && !!(st->st_size));
    case 'S':
	return (S_ISSOCK(dostat(c->left)));
    case 'u':
	return (!!(dostat(c->left) & S_ISUID));
    case 'w':
	return (doaccess(c->left, W_OK));
    case 'x':
	return (doaccess(c->left, X_OK));
    case 'z':
	return (!strlen(c->left));
    case 'h':
    case 'L':
	return (S_ISLNK(dolstat(c->left)));
    case 'O':
	return ((st = getstat(c->left)) && st->st_uid == geteuid());
    case 'G':
	return ((st = getstat(c->left)) && st->st_gid == getegid());
    case 't':
	return isatty(matheval(c->left));
    case COND_EQ:
	return matheval(c->left) == matheval(c->right);
    case COND_NE:
	return matheval(c->left) != matheval(c->right);
    case COND_LT:
	return matheval(c->left) < matheval(c->right);
    case COND_GT:
	return matheval(c->left) > matheval(c->right);
    case COND_LE:
	return matheval(c->left) <= matheval(c->right);
    case COND_GE:
	return matheval(c->left) >= matheval(c->right);
    case COND_NT:
    case COND_OT:
	{
	    time_t a;

	    if (!(st = getstat(c->left)))
		return 0;
	    a = st->st_mtime;
	    if (!(st = getstat(c->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(c->left)))
		return 0;
	    d = st->st_dev;
	    i = st->st_ino;
	    if (!(st = getstat(c->right)))
		return 0;
	    return d == st->st_dev && i == st->st_ino;
	}
    default:
	zerr("bad cond structure", NULL, 0);
    }
    return 0;
}

int doaccess(s, c)		/**/
char *s;
int c;
{
    return !access(s, c);
}

static struct stat st;

struct stat *getstat(s)		/**/
char *s;
{
    if (!strncmp(s, "/dev/fd/", 8)) {
	if (fstat(atoi(s + 8), &st))
	    return NULL;
    } else if (stat(s, &st))
	return NULL;
    return &st;
}

unsigned short dostat(s)	/**/
char *s;
{
    struct stat *statp;

    if (!(statp = getstat(s)))
	return 0;
    return statp->st_mode;
}

/* pem@aaii.oz; needed since dostat now uses "stat" */

unsigned short dolstat(s)	/**/
char *s;
{
    if (lstat(s, &st) < 0)
	return 0;
    return st.st_mode;
}

int optison(s)			/**/
char *s;
{
    int i;

    if (strlen(s) == 1)
	return opts[(int)*s];
    if ((i = optlookup(s)) != -1)
	return opts[i];
    zerr("no such option: %s", s, 0);
    return 0;
}
