int execcase(Estate state, int do_exec) { Wordcode end, next; wordcode code = state->pc[-1]; char *word, *pat; int npat, save, nalts, ialt, patok; Patprog *spprog, pprog; end = state->pc + WC_CASE_SKIP(code); word = ecgetstr(state, EC_DUP, NULL); singsub(&word); untokenize(word); cmdpush(CS_CASE); while (state->pc < end) { code = *state->pc++; if (wc_code(code) != WC_CASE) break; save = 0; next = state->pc + WC_CASE_SKIP(code); nalts = *state->pc++; ialt = patok = 0; if (isset(XTRACE)) { printprompt4(); fprintf(xtrerr, "case %s (", word); } while (!patok && nalts) { npat = state->pc[1]; spprog = state->prog->pats + npat; pprog = NULL; pat = NULL; if (isset(XTRACE)) { int htok = 0; pat = dupstring(ecrawstr(state->prog, state->pc, &htok)); if (htok) singsub(&pat); if (ialt++) fprintf(stderr, " | "); quote_tokenized_output(pat, xtrerr); } if (*spprog != dummy_patprog1 && *spprog != dummy_patprog2) pprog = *spprog; if (!pprog) { if (!pat) { char *opat; int htok = 0; pat = dupstring(opat = ecrawstr(state->prog, state->pc, &htok)); if (htok) singsub(&pat); save = (!(state->prog->flags & EF_HEAP) && !strcmp(pat, opat) && *spprog != dummy_patprog2); } if (!(pprog = patcompile(pat, (save ? PAT_ZDUP : PAT_STATIC), NULL))) zerr("bad pattern: %s", pat); else if (save) *spprog = pprog; } if (pprog && pattry(pprog, word)) patok = 1; state->pc += 2; nalts--; } state->pc += 2 * nalts; if (isset(XTRACE)) { fprintf(xtrerr, ")\n"); fflush(xtrerr); } if (patok) { execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) && do_exec)); while (!retflag && wc_code(code) == WC_CASE && WC_CASE_TYPE(code) == WC_CASE_AND && state->pc < end) { state->pc = next; code = *state->pc++; next = state->pc + WC_CASE_SKIP(code); nalts = *state->pc++; state->pc += 2 * nalts; execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) && do_exec)); } if (WC_CASE_TYPE(code) != WC_CASE_TESTAND) break; } state->pc = next; } cmdpop(); state->pc = end; return lastval; }
static int do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod) { switch (test) { case CVT_RANGENUM: { int l = arrlen(compwords); if (na < 0) na += l; else na--; if (nb < 0) nb += l; else nb--; if (compcurrent - 1 < na || compcurrent - 1 > nb) return 0; if (mod) restrict_range(na, nb); return 1; } case CVT_RANGEPAT: { char **p; int i, l = arrlen(compwords), t = 0, b = 0, e = l - 1; Patprog pp; i = compcurrent - 1; if (i < 0 || i >= l) return 0; singsub(&sa); pp = patcompile(sa, PAT_STATIC, NULL); for (i--, p = compwords + i; i >= 0; p--, i--) { if (pattry(pp, *p)) { b = i + 1; t = 1; break; } } if (t && sb) { int tt = 0; singsub(&sb); pp = patcompile(sb, PAT_STATIC, NULL); for (i++, p = compwords + i; i < l; p++, i++) { if (pattry(pp, *p)) { e = i - 1; tt = 1; break; } } if (tt && i < compcurrent) t = 0; } if (e < b) t = 0; if (t && mod) restrict_range(b, e); return t; } case CVT_PRENUM: case CVT_SUFNUM: if (!na) return 1; if (na > 0 && (int)strlen(test == CVT_PRENUM ? compprefix : compsuffix) >= na) { if (mod) { if (test == CVT_PRENUM) ignore_prefix(na); else ignore_suffix(na); return 1; } return 0; } case CVT_PREPAT: case CVT_SUFPAT: { Patprog pp; if (!na) return 0; if (!(pp = patcompile(sa, PAT_STATIC, 0))) return 0; if (test == CVT_PREPAT) { int l, add; char *p, sav; if (!(l = strlen(compprefix))) return ((na == 1 || na == -1) && pattry(pp, compprefix)); if (na < 0) { p = compprefix + l; na = -na; add = -1; } else { p = compprefix + 1 + (*compprefix == Meta); if (p > compprefix + l) p = compprefix + l; add = 1; } for (;;) { sav = *p; *p = '\0'; test = pattry(pp, compprefix); *p = sav; if (test && !--na) break; if (add > 0) { if (p == compprefix + l) return 0; p = p + 1 + (*p == Meta); if (p > compprefix + l) p = compprefix + l; } else { if (p == compprefix) return 0; p--; if (p > compprefix && p[-1] == Meta) p--; } } if (mod) ignore_prefix(p - compprefix); } else { int l, ol, add; char *p; if (!(ol = l = strlen(compsuffix))) return ((na == 1 || na == -1) && pattry(pp, compsuffix)); if (na < 0) { p = compsuffix; na = -na; add = 1; } else { p = compsuffix + l - 1; if (p > compsuffix && p[-1] == Meta) p--; add = -1; } for (;;) { if (pattry(pp, p) && !--na) break; if (add > 0) { if (p == compsuffix + l) return 0; if (*p == Meta) p += 2; else p++; } else { if (p == compsuffix) return 0; p--; if (p > compsuffix && p[-1] == Meta) p--; } } if (mod) ignore_suffix(ol - (p - compsuffix)); } return 1; } } return 0; }
int bin_setopt(char *nam, char **args, UNUSED(Options ops), int isun) { int action, optno, match = 0; /* With no arguments or options, display options. */ if (!*args) { scanhashtable(optiontab, 1, 0, OPT_ALIAS, optiontab->printnode, !isun); return 0; } /* loop through command line options (begins with "-" or "+") */ while (*args && (**args == '-' || **args == '+')) { action = (**args == '-') ^ isun; if(!args[0][1]) *args = "--"; while (*++*args) { if(**args == Meta) *++*args ^= 32; /* The pseudo-option `--' signifies the end of options. */ if (**args == '-') { args++; goto doneoptions; } else if (**args == 'o') { if (!*++*args) args++; if (!*args) { zwarnnam(nam, "string expected after -o"); inittyptab(); return 1; } if(!(optno = optlookup(*args))) zwarnnam(nam, "no such option: %s", *args); else if(dosetopt(optno, action, 0, opts)) zwarnnam(nam, "can't change option: %s", *args); break; } else if(**args == 'm') { match = 1; } else { if (!(optno = optlookupc(**args))) zwarnnam(nam, "bad option: -%c", **args); else if(dosetopt(optno, action, 0, opts)) zwarnnam(nam, "can't change option: -%c", **args); } } args++; } doneoptions: if (!match) { /* Not globbing the arguments -- arguments are simply option names. */ while (*args) { if(!(optno = optlookup(*args++))) zwarnnam(nam, "no such option: %s", args[-1]); else if(dosetopt(optno, !isun, 0, opts)) zwarnnam(nam, "can't change option: %s", args[-1]); } } else { /* Globbing option (-m) set. */ while (*args) { Patprog pprog; char *s, *t; t = s = dupstring(*args); while (*t) if (*t == '_') chuck(t); else { /* See comment in optlookup() */ if (*t >= 'A' && *t <= 'Z') *t = (*t - 'A') + 'a'; t++; } /* Expand the current arg. */ tokenize(s); if (!(pprog = patcompile(s, PAT_STATIC, NULL))) { zwarnnam(nam, "bad pattern: %s", *args); continue; } /* Loop over expansions. */ scanmatchtable(optiontab, pprog, 0, 0, OPT_ALIAS, setoption, !isun); args++; } } inittyptab(); return 0; }
int evalcond(Estate state, char *fromtest) { struct stat *st; char *left, *right, *overridename, overridebuf[13]; Wordcode pcode; wordcode code; int ctype, htok = 0, ret; rec: left = right = overridename = 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_REGEX: { char *modname = isset(REMATCHPCRE) ? "zsh/pcre" : "zsh/regex"; sprintf(overridename = overridebuf, "-%s-match", modname+4); (void)ensurefeature(modname, "C:", overridename+1); ctype = COND_MODI; } /*FALLTHROUGH*/ case COND_MOD: case COND_MODI: { Conddef cd; char *name = overridename, *errname; char **strs; int l = WC_COND_SKIP(code); if (name == NULL) name = ecgetstr(state, EC_NODUP, NULL); 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 (name && name[0] == '-') errname = name; else if (strs[0] && *strs[0] == '-') errname = strs[0]; else errname = "<null>"; if (name && name[0] == '-' && (cd = getconddef((ctype == COND_MODI), name + 1, 1))) { if (ctype == COND_MOD && (l < cd->min || (cd->max >= 0 && l > cd->max))) { zwarnnam(fromtest, "unknown condition: %s", name); return 2; } if (tracingcond) tracemodcond(name, strs, ctype == COND_MODI); return !cd->handler(strs, cd->condid); } else { char *s = strs[0]; if (overridename) { /* * Standard regex function not available: this * is a hard error. */ zerrnam(fromtest, "%s not available for regex", overridename); return 2; } 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, "unknown condition: %s", errname); return 2; } if (tracingcond) tracemodcond(name, strs, ctype == COND_MODI); return !cd->handler(strs, cd->condid); } else { zwarnnam(fromtest, "unknown condition: %s", errname); } } /* module not found, error */ return 2; } } left = ecgetstr(state, EC_DUPTOK, &htok); if (htok) { cond_subst(&left, !fromtest); untokenize(left); } if (ctype <= COND_GE && ctype != COND_STREQ && ctype != COND_STRNEQ) { right = ecgetstr(state, EC_DUPTOK, &htok); if (htok) { cond_subst(&right, !fromtest); untokenize(right); } } if (tracingcond) { if (ctype < COND_MOD) { fputc(' ',xtrerr); quotedzputs(left, xtrerr); fprintf(xtrerr, " %s ", condstr[ctype]); if (ctype == COND_STREQ || ctype == COND_STRNEQ) { char *rt = dupstring(ecrawstr(state->prog, state->pc, NULL)); cond_subst(&rt, !fromtest); quote_tokenized_output(rt, xtrerr); } else quotedzputs((char *)right, 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); 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)); 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); 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': #if defined(GET_ST_MTIME_NSEC) && defined(GET_ST_ATIME_NSEC) if (!(st = getstat(left))) return 1; return (st->st_atime == st->st_mtime) ? GET_ST_ATIME_NSEC(*st) > GET_ST_MTIME_NSEC(*st) : st->st_atime > st->st_mtime; #else return !((st = getstat(left)) && st->st_atime <= st->st_mtime); #endif case 't': return !isatty(mathevali(left)); case COND_NT: case COND_OT: { time_t a; #ifdef GET_ST_MTIME_NSEC long nsecs; #endif if (!(st = getstat(left))) return 1; a = st->st_mtime; #ifdef GET_ST_MTIME_NSEC nsecs = GET_ST_MTIME_NSEC(*st); #endif if (!(st = getstat(right))) return 1; #ifdef GET_ST_MTIME_NSEC if (a == st->st_mtime) { return !((ctype == COND_NT) ? nsecs > GET_ST_MTIME_NSEC(*st) : nsecs < GET_ST_MTIME_NSEC(*st)); } #endif 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"); return 2; } }
static int ptyread(char *nam, Ptycmd cmd, char **args, int noblock, int mustmatch) { int blen, used, seen = 0, ret = 0, matchok = 0; char *buf; Patprog prog = NULL; if (*args && args[1]) { char *p; if (args[2]) { zwarnnam(nam, "too many arguments"); return 1; } p = dupstring(args[1]); tokenize(p); remnulargs(p); /* Signals handlers might stomp PAT_STATIC */ if (!(prog = patcompile(p, PAT_ZDUP, NULL))) { zwarnnam(nam, "bad pattern: %s", args[1]); return 1; } } else fflush(stdout); if (cmd->old) { used = cmd->olen; buf = (char *) zhalloc((blen = 256 + used) + 1); memcpy(buf, cmd->old, cmd->olen); zfree(cmd->old, cmd->olen); cmd->old = NULL; cmd->olen = 0; } else { used = 0; buf = (char *) zhalloc((blen = 256) + 1); } if (cmd->read != -1) { buf[used] = (char) cmd->read; buf[used + 1] = '\0'; seen = used = 1; cmd->read = -1; } do { if (noblock && cmd->read == -1) { int pollret; /* * Check there is data available. Borrowed from * poll_read() in utils.c and simplified. */ #ifdef HAVE_SELECT fd_set foofd; struct timeval expire_tv; expire_tv.tv_sec = 0; expire_tv.tv_usec = 0; FD_ZERO(&foofd); FD_SET(cmd->fd, &foofd); pollret = select(cmd->fd+1, (SELECT_ARG_2_T) &foofd, NULL, NULL, &expire_tv); #else #ifdef FIONREAD if (ioctl(cmd->fd, FIONREAD, (char *) &val) == 0) pollret = (val > 0); #endif #endif if (pollret < 0) { /* * See read_poll() for this. * Last despairing effort to poll: attempt to * set nonblocking I/O and actually read the * character. cmd->read stores the character read. */ long mode; if (setblock_fd(0, cmd->fd, &mode)) pollret = read(cmd->fd, &cmd->read, 1); if (mode != -1) fcntl(cmd->fd, F_SETFL, mode); } if (pollret == 0) break; } if (!ret) { checkptycmd(cmd); if (cmd->fin) break; } if (cmd->read != -1 || (ret = read(cmd->fd, buf + used, 1)) == 1) { int readchar; if (cmd->read != -1) { ret = 1; readchar = cmd->read; cmd->read = -1; } else readchar = STOUC(buf[used]); if (imeta(readchar)) { buf[used++] = Meta; buf[used++] = (char) (readchar ^ 32); } else buf[used++] = (char) readchar; seen = 1; if (used >= blen-1) { if (!*args) { buf[used] = '\0'; unmetafy(buf, &used); write_loop(1, buf, used); used = 0; } else { buf = hrealloc(buf, blen, blen << 1); blen <<= 1; } } } buf[used] = '\0'; if (!prog) { if (ret <= 0 || (*args && buf[used - 1] == '\n' && (used < 2 || buf[used-2] != Meta))) break; } else { if (ret < 0 #ifdef EWOULDBLOCK && errno != EWOULDBLOCK #else #ifdef EAGAIN && errno != EAGAIN #endif #endif ) break; } } while (!(errflag || breaks || retflag || contflag) && used < READ_MAX && !(prog && ret && (matchok = pattry(prog, buf)))); if (prog && ret < 0 && #ifdef EWOULDBLOCK errno == EWOULDBLOCK #else #ifdef EAGAIN errno == EAGAIN #endif #endif ) { cmd->old = (char *) zalloc(cmd->olen = used); memcpy(cmd->old, buf, cmd->olen); return 1; } if (*args) setsparam(*args, ztrdup(buf)); else if (used) { unmetafy(buf, &used); write_loop(1, buf, used); } { int ret = cmd->fin + 1; if (seen && (!prog || matchok || !mustmatch)) ret = 0; if (prog) freepatprog(prog); return ret; } }