diff -r 000000000000 -r 2e3d3ce01487 openenvutils/commandshell/shell/src/cond.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/openenvutils/commandshell/shell/src/cond.c Tue Feb 02 10:12:00 2010 +0200 @@ -0,0 +1,500 @@ +/* + * 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" +}; + +/* + * Evaluate a conditional expression given the arguments. + * If fromtest is set, the caller is the test or [ builtin; + * with the pointer giving the name of the command. + * for POSIX conformance this supports a more limited range + * of functionality. + * + * Return status is the final shell status, i.e. 0 for true, + * 1 for false and 2 for error. + */ + +/**/ +int +evalcond(Estate state, char *fromtest) +{ + struct stat *st; + char *left, *right; + Wordcode pcode; + wordcode code; + int ctype, htok = 0, ret; + + 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]); + ret = evalcond(state, fromtest); + if (ret == 2) + return ret; + else + return !ret; + case COND_AND: + if (!(ret = evalcond(state, fromtest))) { + if (tracingcond) + fprintf(xtrerr, " %s", condstr[ctype]); + goto rec; + } else { + state->pc = pcode + (WC_COND_SKIP(code) + 1); + return ret; + } + case COND_OR: + if ((ret = evalcond(state, fromtest)) == 1) { + if (tracingcond) + fprintf(xtrerr, " %s", condstr[ctype]); + goto rec; + } else { + state->pc = pcode + (WC_COND_SKIP(code) + 1); + return ret; + } + 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))) { + zwarnnam(fromtest, "unrecognized condition: `%s'", + name, 0); + return 2; + } + 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)) { + zwarnnam(fromtest, "unrecognized condition: `%s'", + name, 0); + return 2; + } + if (tracingcond) + tracemodcond(name, strs, ctype == COND_MODI); + return !cd->handler(strs, cd->condid); + } else { + zwarnnam(fromtest, + "unrecognized condition: `%s'", name, 0); + } + } + /* module not found, error */ + return 2; + } + } + 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); + } + fputc(' ',xtrerr); + quotedzputs(left, xtrerr); + fprintf(xtrerr, " %s ", condstr[ctype]); + quotedzputs(rt, xtrerr); + } else { + fprintf(xtrerr, " -%c ", ctype); + quotedzputs(left, xtrerr); + } + } + + if (ctype >= COND_EQ && ctype <= COND_GE) { + mnumber mn1, mn2; + if (fromtest) { + /* + * For test and [, the expressions must be base 10 integers, + * not integer expressions. + */ + char *eptr, *err; + + mn1.u.l = zstrtol(left, &eptr, 10); + if (!*eptr) + { + mn2.u.l = zstrtol(right, &eptr, 10); + err = right; + } + else + err = left; + + if (*eptr) + { + zwarnnam(fromtest, "integer expression expected: %s", + err, 0); + return 2; + } + + mn1.type = mn2.type = MN_INTEGER; + } else { + 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 = dupstring(opat = ecrawstr(state->prog, state->pc, + &htok)); + if (htok) + singsub(&right); + save = (!(state->prog->flags & EF_HEAP) && + !strcmp(opat, right) && pprog != dummy_patprog2); + + if (!(pprog = patcompile(right, (save ? PAT_ZDUP : PAT_STATIC), + NULL))) { + zwarnnam(fromtest, "bad pattern: %s", right, 0); + return 2; + } + 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(fromtest, 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 1; + a = st->st_mtime; + if (!(st = getstat(right))) + return 1; + 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 1; + d = st->st_dev; + i = st->st_ino; + if (!(st = getstat(right))) + return 1; + return !(d == st->st_dev && i == st->st_ino); + } + default: + zwarnnam(fromtest, "bad cond code", NULL, 0); + return 2; + } + return 1; +} + + +/**/ +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) +{ + char *us; + +/* /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 (!(us = unmeta(s))) + return NULL; + if (stat(us, &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; +} + + +/* + * optison returns evalcond-friendly statuses (true, false, error). + */ + +/**/ +static int +optison(char *name, char *s) +{ + int i; + + if (strlen(s) == 1) + i = optlookupc(*s); + else + i = optlookup(s); + if (!i) { + zwarnnam(name, "no such option: %s", s, 0); + return 2; + } 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++); + } +}