summaryrefslogtreecommitdiff
path: root/Src/cond.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/cond.c')
-rw-r--r--Src/cond.c326
1 files changed, 269 insertions, 57 deletions
diff --git a/Src/cond.c b/Src/cond.c
index 79886a720..8a54eeeb2 100644
--- a/Src/cond.c
+++ b/Src/cond.c
@@ -30,125 +30,277 @@
#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)
+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 (c->type) {
+ switch (ctype) {
case COND_NOT:
- return !evalcond(c->left);
+ if (tracingcond)
+ fprintf(xtrerr, " %s", condstr[ctype]);
+ return !evalcond(state);
case COND_AND:
- return evalcond(c->left) && evalcond(c->right);
+ 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:
- return evalcond(c->left) || evalcond(c->right);
+ 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;
+ }
}
- 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);
+ left = ecgetstr(state, EC_DUPTOK, &htok);
+ if (htok) {
+ singsub(&left);
+ untokenize(left);
}
- switch (c->type) {
+ 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:
- return matchpat(c->left, c->right);
case COND_STRNEQ:
- return !matchpat(c->left, c->right);
+ {
+ 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->flags & EF_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(c->left, c->right) < 0;
+ return strcmp(left, right) < 0;
case COND_STRGTR:
- return strcmp(c->left, c->right) > 0;
+ return strcmp(left, right) > 0;
case 'e':
case 'a':
- return (doaccess(c->left, F_OK));
+ return (doaccess(left, F_OK));
case 'b':
- return (S_ISBLK(dostat(c->left)));
+ return (S_ISBLK(dostat(left)));
case 'c':
- return (S_ISCHR(dostat(c->left)));
+ return (S_ISCHR(dostat(left)));
case 'd':
- return (S_ISDIR(dostat(c->left)));
+ return (S_ISDIR(dostat(left)));
case 'f':
- return (S_ISREG(dostat(c->left)));
+ return (S_ISREG(dostat(left)));
case 'g':
- return (!!(dostat(c->left) & S_ISGID));
+ return (!!(dostat(left) & S_ISGID));
case 'k':
- return (!!(dostat(c->left) & S_ISVTX));
+ return (!!(dostat(left) & S_ISVTX));
case 'n':
- return (!!strlen(c->left));
+ return (!!strlen(left));
case 'o':
- return (optison(c->left));
+ return (optison(left));
case 'p':
- return (S_ISFIFO(dostat(c->left)));
+ return (S_ISFIFO(dostat(left)));
case 'r':
- return (doaccess(c->left, R_OK));
+ return (doaccess(left, R_OK));
case 's':
- return ((st = getstat(c->left)) && !!(st->st_size));
+ return ((st = getstat(left)) && !!(st->st_size));
case 'S':
- return (S_ISSOCK(dostat(c->left)));
+ return (S_ISSOCK(dostat(left)));
case 'u':
- return (!!(dostat(c->left) & S_ISUID));
+ return (!!(dostat(left) & S_ISUID));
case 'w':
- return (doaccess(c->left, W_OK));
+ return (doaccess(left, W_OK));
case 'x':
if (privasserted()) {
- mode_t mode = dostat(c->left);
+ mode_t mode = dostat(left);
return (mode & S_IXUGO) || S_ISDIR(mode);
}
- return doaccess(c->left, X_OK);
+ return doaccess(left, X_OK);
case 'z':
- return (!strlen(c->left));
+ return (!strlen(left));
case 'h':
case 'L':
- return (S_ISLNK(dolstat(c->left)));
+ return (S_ISLNK(dolstat(left)));
case 'O':
- return ((st = getstat(c->left)) && st->st_uid == geteuid());
+ return ((st = getstat(left)) && st->st_uid == geteuid());
case 'G':
- return ((st = getstat(c->left)) && st->st_gid == getegid());
+ return ((st = getstat(left)) && st->st_gid == getegid());
case 'N':
- return ((st = getstat(c->left)) && st->st_atime <= st->st_mtime);
+ return ((st = getstat(left)) && st->st_atime <= st->st_mtime);
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);
+ return isatty(mathevali(left));
case COND_NT:
case COND_OT:
{
time_t a;
- if (!(st = getstat(c->left)))
+ if (!(st = getstat(left)))
return 0;
a = st->st_mtime;
- if (!(st = getstat(c->right)))
+ if (!(st = getstat(right)))
return 0;
- return (c->type == COND_NT) ? a > st->st_mtime : a < st->st_mtime;
+ return (ctype == COND_NT) ? a > st->st_mtime : a < st->st_mtime;
}
case COND_EF:
{
dev_t d;
ino_t i;
- if (!(st = getstat(c->left)))
+ if (!(st = getstat(left)))
return 0;
d = st->st_dev;
i = st->st_ino;
- if (!(st = getstat(c->right)))
+ if (!(st = getstat(right)))
return 0;
return d == st->st_dev && i == st->st_ino;
}
default:
- zerr("bad cond structure", NULL, 0);
+ zerr("bad cond code", NULL, 0);
}
return 0;
}
@@ -158,6 +310,10 @@ evalcond(Cond c)
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);
}
@@ -224,3 +380,59 @@ optison(char *s)
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++);
+ }
+}