diff options
Diffstat (limited to 'Src/cond.c')
-rw-r--r-- | Src/cond.c | 326 |
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++); + } +} |