static void taddassign(wordcode code, Estate state, int typeset) { /* name */ taddstr(ecgetstr(state, EC_NODUP, NULL)); /* value... maybe */ if (WC_ASSIGN_TYPE2(code) == WC_ASSIGN_INC) { if (typeset) { /* dummy assignment --- just var name */ (void)ecgetstr(state, EC_NODUP, NULL); taddchr(' '); return; } taddchr('+'); } taddchr('='); if (WC_ASSIGN_TYPE(code) == WC_ASSIGN_ARRAY) { taddchr('('); taddlist(state, WC_ASSIGN_NUM(code)); taddstr(") "); } else { taddstr(ecgetstr(state, EC_NODUP, NULL)); taddchr(' '); } }
static void taddlist(Estate state, int num) { if (num) { while (num--) { taddstr(ecgetstr(state, EC_NODUP, NULL)); taddchr(' '); } tptr--; } }
int execrepeat(Estate state, UNUSED(int do_exec)) { Wordcode end, loop; wordcode code = state->pc[-1]; int count, htok = 0; char *tmp; int old_simple_pline = simple_pline; /* See comments in execwhile() */ simple_pline = 1; end = state->pc + WC_REPEAT_SKIP(code); lastval = 0; tmp = ecgetstr(state, EC_DUPTOK, &htok); if (htok) singsub(&tmp); count = mathevali(tmp); if (errflag) return 1; pushheap(); cmdpush(CS_REPEAT); loops++; loop = state->pc; while (count-- > 0) { state->pc = loop; execlist(state, 1, 0); freeheap(); if (breaks) { breaks--; if (breaks || !contflag) break; contflag = 0; } if (errflag) { lastval = 1; break; } if (retflag) break; } cmdpop(); popheap(); loops--; simple_pline = old_simple_pline; state->pc = end; this_noerrexit = 1; return lastval; }
int execrepeat(Estate state, UNUSED(int do_exec)) { Wordcode end, loop; wordcode code = state->pc[-1]; int count, htok = 0; char *tmp; end = state->pc + WC_REPEAT_SKIP(code); lastval = 0; tmp = ecgetstr(state, EC_DUPTOK, &htok); if (htok) singsub(&tmp); count = atoi(tmp); pushheap(); cmdpush(CS_REPEAT); loops++; loop = state->pc; while (count-- > 0) { state->pc = loop; execlist(state, 1, 0); freeheap(); if (breaks) { breaks--; if (breaks || !contflag) break; contflag = 0; } if (errflag) { lastval = 1; break; } if (retflag) break; } cmdpop(); popheap(); loops--; state->pc = end; return lastval; }
static void gettext2(Estate state) { Tstack s, n; int stack = 0; wordcode code; while (1) { if (stack) { if (!(s = tstack)) break; if (s->pop) { tstack = s->prev; s->prev = tfree; tfree = s; } code = s->code; stack = 0; } else { s = NULL; code = *state->pc++; } switch (wc_code(code)) { case WC_LIST: if (!s) { s = tpush(code, (WC_LIST_TYPE(code) & Z_END)); stack = 0; } else { if (WC_LIST_TYPE(code) & Z_ASYNC) { taddstr(" &"); if (WC_LIST_TYPE(code) & Z_DISOWN) taddstr("|"); } if (!(stack = (WC_LIST_TYPE(code) & Z_END))) { if (tnewlins) taddnl(0); else taddstr((WC_LIST_TYPE(code) & Z_ASYNC) ? " " : "; "); s->code = *state->pc++; s->pop = (WC_LIST_TYPE(s->code) & Z_END); } } if (!stack && (WC_LIST_TYPE(s->code) & Z_SIMPLE)) state->pc++; break; case WC_SUBLIST: if (!s) { if (!(WC_SUBLIST_FLAGS(code) & WC_SUBLIST_SIMPLE) && wc_code(*state->pc) != WC_PIPE) stack = -1; if (WC_SUBLIST_FLAGS(code) & WC_SUBLIST_NOT) taddstr(stack ? "!" : "! "); if (WC_SUBLIST_FLAGS(code) & WC_SUBLIST_COPROC) taddstr(stack ? "coproc" : "coproc "); s = tpush(code, (WC_SUBLIST_TYPE(code) == WC_SUBLIST_END)); } else { if (!(stack = (WC_SUBLIST_TYPE(code) == WC_SUBLIST_END))) { taddstr((WC_SUBLIST_TYPE(code) == WC_SUBLIST_OR) ? " || " : " && "); s->code = *state->pc++; s->pop = (WC_SUBLIST_TYPE(s->code) == WC_SUBLIST_END); if (WC_SUBLIST_FLAGS(s->code) & WC_SUBLIST_NOT) taddstr("! "); if (WC_SUBLIST_FLAGS(s->code) & WC_SUBLIST_COPROC) taddstr("coproc "); } } if (stack < 1 && (WC_SUBLIST_FLAGS(s->code) & WC_SUBLIST_SIMPLE)) state->pc++; break; case WC_PIPE: if (!s) { tpush(code, (WC_PIPE_TYPE(code) == WC_PIPE_END)); if (WC_PIPE_TYPE(code) == WC_PIPE_MID) state->pc++; } else { if (!(stack = (WC_PIPE_TYPE(code) == WC_PIPE_END))) { taddstr(" | "); s->code = *state->pc++; if (!(s->pop = (WC_PIPE_TYPE(s->code) == WC_PIPE_END))) state->pc++; } } break; case WC_REDIR: if (!s) { state->pc--; n = tpush(code, 1); n->u._redir.list = ecgetredirs(state); } else { getredirs(s->u._redir.list); stack = 1; } break; case WC_ASSIGN: taddstr(ecgetstr(state, EC_NODUP, NULL)); if (WC_ASSIGN_TYPE2(code) == WC_ASSIGN_INC) taddchr('+'); taddchr('='); if (WC_ASSIGN_TYPE(code) == WC_ASSIGN_ARRAY) { taddchr('('); taddlist(state, WC_ASSIGN_NUM(code)); taddstr(") "); } else { taddstr(ecgetstr(state, EC_NODUP, NULL)); taddchr(' '); } break; case WC_SIMPLE: taddlist(state, WC_SIMPLE_ARGC(code)); stack = 1; break; case WC_SUBSH: if (!s) { taddstr("("); tindent++; taddnl(1); n = tpush(code, 1); n->u._subsh.end = state->pc + WC_SUBSH_SKIP(code); /* skip word only use for try/always */ state->pc++; } else { state->pc = s->u._subsh.end; dec_tindent(); /* semicolon is optional here but more standard */ taddnl(0); taddstr(")"); stack = 1; } break; case WC_CURSH: if (!s) { taddstr("{"); tindent++; taddnl(1); n = tpush(code, 1); n->u._subsh.end = state->pc + WC_CURSH_SKIP(code); /* skip word only use for try/always */ state->pc++; } else { state->pc = s->u._subsh.end; dec_tindent(); /* semicolon is optional here but more standard */ taddnl(0); taddstr("}"); stack = 1; } break; case WC_TIMED: if (!s) { taddstr("time"); if (WC_TIMED_TYPE(code) == WC_TIMED_PIPE) { taddchr(' '); tindent++; tpush(code, 1); } else stack = 1; } else { dec_tindent(); stack = 1; } break; case WC_FUNCDEF: if (!s) { Wordcode p = state->pc; Wordcode end = p + WC_FUNCDEF_SKIP(code); taddlist(state, *state->pc++); if (tjob) { taddstr(" () { ... }"); state->pc = end; stack = 1; } else { taddstr(" () {"); tindent++; taddnl(1); n = tpush(code, 1); n->u._funcdef.strs = state->strs; n->u._funcdef.end = end; state->strs += *state->pc; state->pc += 3; } } else { state->strs = s->u._funcdef.strs; state->pc = s->u._funcdef.end; dec_tindent(); taddnl(0); taddstr("}"); stack = 1; } break; case WC_FOR: if (!s) { taddstr("for "); if (WC_FOR_TYPE(code) == WC_FOR_COND) { taddstr("(("); taddstr(ecgetstr(state, EC_NODUP, NULL)); taddstr("; "); taddstr(ecgetstr(state, EC_NODUP, NULL)); taddstr("; "); taddstr(ecgetstr(state, EC_NODUP, NULL)); taddstr(")) do"); } else { taddlist(state, *state->pc++); if (WC_FOR_TYPE(code) == WC_FOR_LIST) { taddstr(" in "); taddlist(state, *state->pc++); } taddnl(0); taddstr("do"); } tindent++; taddnl(0); tpush(code, 1); } else { dec_tindent(); taddnl(0); taddstr("done"); stack = 1; } break; case WC_SELECT: if (!s) { taddstr("select "); taddstr(ecgetstr(state, EC_NODUP, NULL)); if (WC_SELECT_TYPE(code) == WC_SELECT_LIST) { taddstr(" in "); taddlist(state, *state->pc++); } tindent++; taddnl(0); tpush(code, 1); } else { dec_tindent(); taddnl(0); taddstr("done"); stack = 1; } break; case WC_WHILE: if (!s) { taddstr(WC_WHILE_TYPE(code) == WC_WHILE_UNTIL ? "until " : "while "); tindent++; tpush(code, 0); } else if (!s->pop) { dec_tindent(); taddnl(0); taddstr("do"); tindent++; taddnl(0); s->pop = 1; } else { dec_tindent(); taddnl(0); taddstr("done"); stack = 1; } break; case WC_REPEAT: if (!s) { taddstr("repeat "); taddstr(ecgetstr(state, EC_NODUP, NULL)); taddnl(0); taddstr("do"); tindent++; taddnl(0); tpush(code, 1); } else { dec_tindent(); taddnl(0); taddstr("done"); stack = 1; } break; case WC_CASE: if (!s) { Wordcode end = state->pc + WC_CASE_SKIP(code); taddstr("case "); taddstr(ecgetstr(state, EC_NODUP, NULL)); taddstr(" in"); if (state->pc >= end) { if (tnewlins) taddnl(0); else taddchr(' '); taddstr("esac"); stack = 1; } else { tindent++; if (tnewlins) taddnl(0); else taddchr(' '); taddstr("("); code = *state->pc++; taddstr(ecgetstr(state, EC_NODUP, NULL)); state->pc++; taddstr(") "); tindent++; n = tpush(code, 0); n->u._case.end = end; n->pop = (state->pc - 2 + WC_CASE_SKIP(code) >= end); } } else if (state->pc < s->u._case.end) { dec_tindent(); switch (WC_CASE_TYPE(code)) { case WC_CASE_OR: taddstr(" ;;"); break; case WC_CASE_AND: taddstr(";&"); break; default: taddstr(";|"); break; } if (tnewlins) taddnl(0); else taddchr(' '); taddstr("("); code = *state->pc++; taddstr(ecgetstr(state, EC_NODUP, NULL)); state->pc++; taddstr(") "); tindent++; s->code = code; s->pop = ((state->pc - 2 + WC_CASE_SKIP(code)) >= s->u._case.end); } else { dec_tindent(); switch (WC_CASE_TYPE(code)) { case WC_CASE_OR: taddstr(" ;;"); break; case WC_CASE_AND: taddstr(";&"); break; default: taddstr(";|"); break; } dec_tindent(); if (tnewlins) taddnl(0); else taddchr(' '); taddstr("esac"); stack = 1; } break; case WC_IF: if (!s) { Wordcode end = state->pc + WC_IF_SKIP(code); taddstr("if "); tindent++; state->pc++; n = tpush(code, 0); n->u._if.end = end; n->u._if.cond = 1; } else if (s->pop) { stack = 1; } else if (s->u._if.cond) { dec_tindent(); taddnl(0); taddstr("then"); tindent++; taddnl(0); s->u._if.cond = 0; } else if (state->pc < s->u._if.end) { dec_tindent(); taddnl(0); code = *state->pc++; if (WC_IF_TYPE(code) == WC_IF_ELIF) { taddstr("elif "); tindent++; s->u._if.cond = 1; } else { taddstr("else"); tindent++; taddnl(0); } } else { s->pop = 1; dec_tindent(); taddnl(0); taddstr("fi"); stack = 1; } break; case WC_COND: { static char *c1[] = { "=", "!=", "<", ">", "-nt", "-ot", "-ef", "-eq", "-ne", "-lt", "-gt", "-le", "-ge", "=~" }; int ctype; if (!s) { taddstr("[[ "); n = tpush(code, 1); n->u._cond.par = 2; } else if (s->u._cond.par == 2) { taddstr(" ]]"); stack = 1; break; } else if (s->u._cond.par == 1) { taddstr(" )"); stack = 1; break; } else if (WC_COND_TYPE(s->code) == COND_AND) { taddstr(" && "); code = *state->pc++; if (WC_COND_TYPE(code) == COND_OR) { taddstr("( "); n = tpush(code, 1); n->u._cond.par = 1; } } else if (WC_COND_TYPE(s->code) == COND_OR) { taddstr(" || "); code = *state->pc++; if (WC_COND_TYPE(code) == COND_AND) { taddstr("( "); n = tpush(code, 1); n->u._cond.par = 1; } } while (!stack) { switch ((ctype = WC_COND_TYPE(code))) { case COND_NOT: taddstr("! "); code = *state->pc++; if (WC_COND_TYPE(code) <= COND_OR) { taddstr("( "); n = tpush(code, 1); n->u._cond.par = 1; } break; case COND_AND: n = tpush(code, 1); n->u._cond.par = 0; code = *state->pc++; if (WC_COND_TYPE(code) == COND_OR) { taddstr("( "); n = tpush(code, 1); n->u._cond.par = 1; } break; case COND_OR: n = tpush(code, 1); n->u._cond.par = 0; code = *state->pc++; if (WC_COND_TYPE(code) == COND_AND) { taddstr("( "); n = tpush(code, 1); n->u._cond.par = 1; } break; case COND_MOD: taddstr(ecgetstr(state, EC_NODUP, NULL)); taddchr(' '); taddlist(state, WC_COND_SKIP(code)); stack = 1; break; case COND_MODI: { char *name = ecgetstr(state, EC_NODUP, NULL); taddstr(ecgetstr(state, EC_NODUP, NULL)); taddchr(' '); taddstr(name); taddchr(' '); taddstr(ecgetstr(state, EC_NODUP, NULL)); stack = 1; } break; default: if (ctype < COND_MOD) { /* Binary test: `a = b' etc. */ taddstr(ecgetstr(state, EC_NODUP, NULL)); taddstr(" "); taddstr(c1[ctype - COND_STREQ]); taddstr(" "); taddstr(ecgetstr(state, EC_NODUP, NULL)); if (ctype == COND_STREQ || ctype == COND_STRNEQ) state->pc++; } else { /* Unary test: `-f foo' etc. */ char c2[4]; c2[0] = '-'; c2[1] = ctype; c2[2] = ' '; c2[3] = '\0'; taddstr(c2); taddstr(ecgetstr(state, EC_NODUP, NULL)); } stack = 1; break; } } } break; case WC_ARITH: taddstr("(("); taddstr(ecgetstr(state, EC_NODUP, NULL)); taddstr("))"); stack = 1; break; case WC_TRY: if (!s) { taddstr("{"); tindent++; taddnl(0); n = tpush(code, 0); state->pc++; /* this is the end of the try block alone */ n->u._subsh.end = state->pc + WC_CURSH_SKIP(state->pc[-1]); } else if (!s->pop) { state->pc = s->u._subsh.end; dec_tindent(); taddnl(0); taddstr("} always {"); tindent++; taddnl(0); s->pop = 1; } else { dec_tindent(); taddnl(0); taddstr("}"); stack = 1; } break; case WC_END: stack = 1; break; default: DPUTS(1, "unknown word code in gettext2()"); return; } } tdopending(); }
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; }
int execfor(Estate state, int do_exec) { Wordcode end, loop; wordcode code = state->pc[-1]; int iscond = (WC_FOR_TYPE(code) == WC_FOR_COND), ctok = 0, atok = 0; int last = 0; char *name, *str, *cond = NULL, *advance = NULL; zlong val = 0; LinkList vars = NULL, args = NULL; int old_simple_pline = simple_pline; /* See comments in execwhile() */ simple_pline = 1; end = state->pc + WC_FOR_SKIP(code); if (iscond) { str = dupstring(ecgetstr(state, EC_NODUP, NULL)); singsub(&str); if (isset(XTRACE)) { char *str2 = dupstring(str); untokenize(str2); printprompt4(); fprintf(xtrerr, "%s\n", str2); fflush(xtrerr); } if (!errflag) { matheval(str); } if (errflag) { state->pc = end; simple_pline = old_simple_pline; return 1; } cond = ecgetstr(state, EC_NODUP, &ctok); advance = ecgetstr(state, EC_NODUP, &atok); } else { vars = ecgetlist(state, *state->pc++, EC_NODUP, NULL); if (WC_FOR_TYPE(code) == WC_FOR_LIST) { int htok = 0; if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) { state->pc = end; simple_pline = old_simple_pline; return 0; } if (htok) { execsubst(args); if (errflag) { state->pc = end; simple_pline = old_simple_pline; return 1; } } } else { char **x; args = newlinklist(); for (x = pparams; *x; x++) addlinknode(args, dupstring(*x)); } } if (!args || empty(args)) lastval = 0; loops++; pushheap(); cmdpush(CS_FOR); loop = state->pc; while (!last) { if (iscond) { if (ctok) { str = dupstring(cond); singsub(&str); } else str = cond; if (!errflag) { while (iblank(*str)) str++; if (*str) { if (isset(XTRACE)) { printprompt4(); fprintf(xtrerr, "%s\n", str); fflush(xtrerr); } val = mathevali(str); } else val = 1; } if (errflag) { if (breaks) breaks--; lastval = 1; break; } if (!val) break; } else { LinkNode node; int count = 0; for (node = firstnode(vars); node; incnode(node)) { name = (char *)getdata(node); if (!args || !(str = (char *) ugetnode(args))) { if (count) { str = ""; last = 1; } else break; } if (isset(XTRACE)) { printprompt4(); fprintf(xtrerr, "%s=%s\n", name, str); fflush(xtrerr); } setsparam(name, ztrdup(str)); count++; } if (!count) break; } state->pc = loop; execlist(state, 1, do_exec && args && empty(args)); if (breaks) { breaks--; if (breaks || !contflag) break; contflag = 0; } if (retflag) break; if (iscond && !errflag) { if (atok) { str = dupstring(advance); singsub(&str); } else str = advance; if (isset(XTRACE)) { printprompt4(); fprintf(xtrerr, "%s\n", str); fflush(xtrerr); } if (!errflag) matheval(str); } if (errflag) { if (breaks) breaks--; lastval = 1; break; } freeheap(); } popheap(); cmdpop(); loops--; simple_pline = old_simple_pline; state->pc = end; return lastval; }
int execselect(Estate state, UNUSED(int do_exec)) { Wordcode end, loop; wordcode code = state->pc[-1]; char *str, *s, *name; LinkNode n; int i, usezle; FILE *inp; size_t more; LinkList args; int old_simple_pline = simple_pline; /* See comments in execwhile() */ simple_pline = 1; end = state->pc + WC_FOR_SKIP(code); name = ecgetstr(state, EC_NODUP, NULL); if (WC_SELECT_TYPE(code) == WC_SELECT_PPARAM) { char **x; args = newlinklist(); for (x = pparams; *x; x++) addlinknode(args, dupstring(*x)); } else { int htok = 0; if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) { state->pc = end; simple_pline = old_simple_pline; return 0; } if (htok) { execsubst(args); if (errflag) { state->pc = end; simple_pline = old_simple_pline; return 1; } } } if (!args || empty(args)) { state->pc = end; simple_pline = old_simple_pline; return 0; } loops++; pushheap(); cmdpush(CS_SELECT); usezle = interact && SHTTY != -1 && isset(USEZLE); inp = fdopen(dup(usezle ? SHTTY : 0), "r"); more = selectlist(args, 0); loop = state->pc; for (;;) { for (;;) { if (empty(bufstack)) { if (usezle) { int oef = errflag; isfirstln = 1; str = zleentry(ZLE_CMD_READ, &prompt3, NULL, 0, ZLCON_SELECT); if (errflag) str = NULL; /* Keep any user interrupt error status */ errflag = oef | (errflag & ERRFLAG_INT); } else { str = promptexpand(prompt3, 0, NULL, NULL, NULL); zputs(str, stderr); free(str); fflush(stderr); str = fgets(zhalloc(256), 256, inp); } } else str = (char *)getlinknode(bufstack); if (!str && !errflag) setsparam("REPLY", ztrdup("")); /* EOF (user pressed Ctrl+D) */ if (!str || errflag) { if (breaks) breaks--; fprintf(stderr, "\n"); fflush(stderr); goto done; } if ((s = strchr(str, '\n'))) *s = '\0'; if (*str) break; more = selectlist(args, more); } setsparam("REPLY", ztrdup(str)); i = atoi(str); if (!i) str = ""; else { for (i--, n = firstnode(args); n && i; incnode(n), i--); if (n) str = (char *) getdata(n); else str = ""; } setsparam(name, ztrdup(str)); state->pc = loop; execlist(state, 1, 0); freeheap(); if (breaks) { breaks--; if (breaks || !contflag) break; contflag = 0; } if (retflag || errflag) break; } done: cmdpop(); popheap(); fclose(inp); loops--; simple_pline = old_simple_pline; state->pc = end; return lastval; }
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; } }