mirror of
				git://git.code.sf.net/p/zsh/code
				synced 2025-11-04 07:21:06 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			438 lines
		
	
	
	
		
			9.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			438 lines
		
	
	
	
		
			9.6 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(Estate state)
 | 
						|
{
 | 
						|
    struct stat *st;
 | 
						|
    char *left, *right;
 | 
						|
    Wordcode pcode;
 | 
						|
    wordcode code;
 | 
						|
    int ctype, htok = 0;
 | 
						|
 | 
						|
 rec:
 | 
						|
 | 
						|
    left = right = NULL;
 | 
						|
    pcode = state->pc++;
 | 
						|
    code = *pcode;
 | 
						|
    ctype = WC_COND_TYPE(code);
 | 
						|
 | 
						|
    switch (ctype) {
 | 
						|
    case COND_NOT:
 | 
						|
	if (tracingcond)
 | 
						|
	    fprintf(xtrerr, " %s", condstr[ctype]);
 | 
						|
	return !evalcond(state);
 | 
						|
    case COND_AND:
 | 
						|
	if (evalcond(state)) {
 | 
						|
	    if (tracingcond)
 | 
						|
		fprintf(xtrerr, " %s", condstr[ctype]);
 | 
						|
	    goto rec;
 | 
						|
	} else {
 | 
						|
	    state->pc = pcode + (WC_COND_SKIP(code) + 1);
 | 
						|
	    return 0;
 | 
						|
	}
 | 
						|
    case COND_OR:
 | 
						|
	if (!evalcond(state)) {
 | 
						|
	    if (tracingcond)
 | 
						|
		fprintf(xtrerr, " %s", condstr[ctype]);
 | 
						|
	    goto rec;
 | 
						|
	} else {
 | 
						|
	    state->pc = pcode + (WC_COND_SKIP(code) + 1);
 | 
						|
	    return 1;
 | 
						|
	}
 | 
						|
    case COND_MOD:
 | 
						|
    case COND_MODI:
 | 
						|
	{
 | 
						|
	    Conddef cd;
 | 
						|
	    char *name = ecgetstr(state, EC_NODUP, NULL), **strs;
 | 
						|
	    int l = WC_COND_SKIP(code);
 | 
						|
 | 
						|
	    if (ctype == COND_MOD)
 | 
						|
		strs = ecgetarr(state, l, EC_DUP, NULL);
 | 
						|
	    else {
 | 
						|
		char *sbuf[3];
 | 
						|
 | 
						|
		sbuf[0] = ecgetstr(state, EC_NODUP, NULL);
 | 
						|
		sbuf[1] = ecgetstr(state, EC_NODUP, NULL);
 | 
						|
		sbuf[2] = NULL;
 | 
						|
 | 
						|
		strs = arrdup(sbuf);
 | 
						|
		l = 2;
 | 
						|
	    }
 | 
						|
	    if ((cd = getconddef((ctype == COND_MODI), name + 1, 1))) {
 | 
						|
		if (ctype == COND_MOD &&
 | 
						|
		    (l < cd->min || (cd->max >= 0 && l > cd->max))) {
 | 
						|
		    zerr("unrecognized condition: `%s'", name, 0);
 | 
						|
		    return 0;
 | 
						|
		}
 | 
						|
		if (tracingcond)
 | 
						|
		    tracemodcond(name, strs, ctype == COND_MODI);
 | 
						|
		return cd->handler(strs, cd->condid);
 | 
						|
	    }
 | 
						|
	    else {
 | 
						|
		char *s = strs[0];
 | 
						|
 | 
						|
		strs[0] = dupstring(name);
 | 
						|
		name = s;
 | 
						|
 | 
						|
		if (name && name[0] == '-' &&
 | 
						|
		    (cd = getconddef(0, name + 1, 1))) {
 | 
						|
		    if (l < cd->min || (cd->max >= 0 && l > cd->max)) {
 | 
						|
			zerr("unrecognized condition: `%s'", name, 0);
 | 
						|
			return 0;
 | 
						|
		    }
 | 
						|
		    if (tracingcond)
 | 
						|
			tracemodcond(name, strs, ctype == COND_MODI);
 | 
						|
		    return cd->handler(strs, cd->condid);
 | 
						|
		} else
 | 
						|
		    zerr("unrecognized condition: `%s'", name, 0);
 | 
						|
	    }
 | 
						|
	    return 0;
 | 
						|
	}
 | 
						|
    }
 | 
						|
    left = ecgetstr(state, EC_DUPTOK, &htok);
 | 
						|
    if (htok) {
 | 
						|
	singsub(&left);
 | 
						|
	untokenize(left);
 | 
						|
    }
 | 
						|
    if (ctype <= COND_GE && ctype != COND_STREQ && ctype != COND_STRNEQ) {
 | 
						|
	right = ecgetstr(state, EC_DUPTOK, &htok);
 | 
						|
	if (htok) {
 | 
						|
	    singsub(&right);
 | 
						|
	    untokenize(right);
 | 
						|
	}
 | 
						|
    }
 | 
						|
    if (tracingcond) {
 | 
						|
	if (ctype < COND_MOD) {
 | 
						|
	    char *rt = (char *) right;
 | 
						|
	    if (ctype == COND_STREQ || ctype == COND_STRNEQ) {
 | 
						|
		rt = dupstring(ecrawstr(state->prog, state->pc, NULL));
 | 
						|
		singsub(&rt);
 | 
						|
		untokenize(rt);
 | 
						|
	    }
 | 
						|
	    fprintf(xtrerr, " %s %s %s", left, condstr[ctype], rt);
 | 
						|
	} else
 | 
						|
	    fprintf(xtrerr, " -%c %s", ctype, left);
 | 
						|
    }
 | 
						|
 | 
						|
    if (ctype >= COND_EQ && ctype <= 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(ctype) {
 | 
						|
	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 (ctype) {
 | 
						|
    case COND_STREQ:
 | 
						|
    case COND_STRNEQ:
 | 
						|
	{
 | 
						|
	    int test, npat = state->pc[1];
 | 
						|
	    Patprog pprog = state->prog->pats[npat];
 | 
						|
 | 
						|
	    if (pprog == dummy_patprog1 || pprog == dummy_patprog2) {
 | 
						|
		char *opat;
 | 
						|
		int save;
 | 
						|
 | 
						|
		right = opat = dupstring(ecrawstr(state->prog, state->pc,
 | 
						|
						  &htok));
 | 
						|
		if (htok)
 | 
						|
		    singsub(&right);
 | 
						|
		save = (state->prog->alloc != EA_HEAP &&
 | 
						|
			!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)
 | 
						|
		    state->prog->pats[npat] = pprog;
 | 
						|
	    }
 | 
						|
	    state->pc += 2;
 | 
						|
	    test = (pprog && pattry(pprog, left));
 | 
						|
 | 
						|
	    return (ctype == 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 (ctype == 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 code", NULL, 0);
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**/
 | 
						|
static int
 | 
						|
doaccess(char *s, int c)
 | 
						|
{
 | 
						|
#ifdef HAVE_FACCESSX
 | 
						|
    if (!strncmp(s, "/dev/fd/", 8))
 | 
						|
	return !faccessx(atoi(s + 8), c, ACC_SELF);
 | 
						|
#endif
 | 
						|
    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);
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export char *
 | 
						|
cond_str(char **args, int num, int raw)
 | 
						|
{
 | 
						|
    char *s = args[num];
 | 
						|
 | 
						|
    if (has_token(s)) {
 | 
						|
	singsub(&s);
 | 
						|
	if (!raw)
 | 
						|
	    untokenize(s);
 | 
						|
    }
 | 
						|
    return s;
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export zlong
 | 
						|
cond_val(char **args, int num)
 | 
						|
{
 | 
						|
    char *s = args[num];
 | 
						|
 | 
						|
    if (has_token(s)) {
 | 
						|
	singsub(&s);
 | 
						|
	untokenize(s);
 | 
						|
    }
 | 
						|
    return mathevali(s);
 | 
						|
}
 | 
						|
 | 
						|
/**/
 | 
						|
mod_export 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;
 | 
						|
 | 
						|
    args = arrdup(args);
 | 
						|
    for (aptr = args; *aptr; aptr++)
 | 
						|
	untokenize(*aptr);
 | 
						|
    if (inf) {
 | 
						|
	fprintf(xtrerr, " %s %s %s", args[0], name, args[1]);
 | 
						|
    } else {
 | 
						|
	fprintf(xtrerr, " %s", name);
 | 
						|
	while (*args)
 | 
						|
	    fprintf(xtrerr, " %s", *args++);
 | 
						|
    }
 | 
						|
}
 |