diff options
Diffstat (limited to 'Src')
-rw-r--r-- | Src/Modules/pcre.c | 68 | ||||
-rw-r--r-- | Src/exec.c | 59 | ||||
-rw-r--r-- | Src/init.c | 4 | ||||
-rw-r--r-- | Src/lex.c | 6 | ||||
-rw-r--r-- | Src/loop.c | 9 | ||||
-rw-r--r-- | Src/module.c | 15 | ||||
-rw-r--r-- | Src/parse.c | 48 | ||||
-rw-r--r-- | Src/signals.c | 2 | ||||
-rw-r--r-- | Src/zsh.h | 23 |
9 files changed, 172 insertions, 62 deletions
diff --git a/Src/Modules/pcre.c b/Src/Modules/pcre.c index 27191d709..659fd22d5 100644 --- a/Src/Modules/pcre.c +++ b/Src/Modules/pcre.c @@ -148,7 +148,7 @@ bin_pcre_study(char *nam, UNUSED(char **args), UNUSED(Options ops), UNUSED(int f /**/ static int -zpcre_get_substrings(char *arg, int *ovec, int ret, char *matchvar, +zpcre_get_substrings(char *arg, int *ovec, int captured_count, char *matchvar, char *substravar, int want_offset_pair, int matchedinarr, int want_begin_end) { @@ -156,15 +156,13 @@ zpcre_get_substrings(char *arg, int *ovec, int ret, char *matchvar, char offset_all[50]; int capture_start = 1; - if (matchedinarr) + if (matchedinarr) { + /* bash-style captures[0] entire-matched string in the array */ capture_start = 0; - if (matchvar == NULL) - matchvar = "MATCH"; - if (substravar == NULL) - substravar = "match"; - + } + /* captures[0] will be entire matched string, [1] first substring */ - if (!pcre_get_substring_list(arg, ovec, ret, (const char ***)&captures)) { + if (!pcre_get_substring_list(arg, ovec, captured_count, (const char ***)&captures)) { int nelem = arrlen(captures)-1; /* Set to the offsets of the complete match */ if (want_offset_pair) { @@ -176,30 +174,43 @@ zpcre_get_substrings(char *arg, int *ovec, int ret, char *matchvar, * difference between the two values in each paired entry in ovec. * ovec is length 2*(1+capture_list_length) */ - match_all = metafy(captures[0], ovec[1] - ovec[0], META_DUP); - setsparam(matchvar, match_all); + if (matchvar) { + match_all = metafy(captures[0], ovec[1] - ovec[0], META_DUP); + setsparam(matchvar, match_all); + } /* * If we're setting match, mbegin, mend we only do * so if there were parenthesised matches, for consistency - * (c.f. regex.c). + * (c.f. regex.c). That's the next block after this one. + * Here we handle the simpler case where we don't worry about + * Unicode lengths, etc. + * Either !want_begin_end (ie, this is bash) or nelem; if bash + * then we're invoked always, even without nelem results, to + * set the array variable with one element in it, the complete match. */ - if (!want_begin_end || nelem) { + if (substravar && + (!want_begin_end || nelem)) { char **x, **y; - int vec_off; + int vec_off, i; y = &captures[capture_start]; - matches = x = (char **) zalloc(sizeof(char *) * (arrlen(y) + 1)); - vec_off = 2; - do { + matches = x = (char **) zalloc(sizeof(char *) * (captured_count+1-capture_start)); + for (i = capture_start; i < captured_count; i++, y++) { + vec_off = 2*i; if (*y) *x++ = metafy(*y, ovec[vec_off+1]-ovec[vec_off], META_DUP); else *x++ = NULL; - vec_off += 2; - } while (*y++); + } + *x = NULL; setaparam(substravar, matches); } if (want_begin_end) { + /* + * cond-infix rather than builtin; also not bash; so we set a bunch + * of variables and arrays to values which require handling Unicode + * lengths + */ char *ptr = arg; zlong offs = 0; int clen, leftlen; @@ -306,7 +317,9 @@ bin_pcre_match(char *nam, char **args, Options ops, UNUSED(int func)) zwarnnam(nam, "no pattern has been compiled"); return 1; } - + + matched_portion = "MATCH"; + receptacle = "match"; if(OPT_HASARG(ops,c='a')) { receptacle = OPT_ARG(ops,c); } @@ -318,8 +331,8 @@ bin_pcre_match(char *nam, char **args, Options ops, UNUSED(int func)) return 1; } /* For the entire match, 'Return' the offset byte positions instead of the matched string */ - if(OPT_ISSET(ops,'b')) want_offset_pair = 1; - + if(OPT_ISSET(ops,'b')) want_offset_pair = 1; + if ((ret = pcre_fullinfo(pcre_pattern, pcre_hints, PCRE_INFO_CAPTURECOUNT, &capcount))) { zwarnnam(nam, "error %d in fullinfo", ret); @@ -360,7 +373,7 @@ cond_pcre_match(char **a, int id) { pcre *pcre_pat; const char *pcre_err; - char *lhstr, *rhre, *lhstr_plain, *rhre_plain, *avar=NULL; + char *lhstr, *rhre, *lhstr_plain, *rhre_plain, *avar, *svar; int r = 0, pcre_opts = 0, pcre_errptr, capcnt, *ov, ovsize; int lhstr_plain_len, rhre_plain_len; int return_value = 0; @@ -380,8 +393,13 @@ cond_pcre_match(char **a, int id) ov = NULL; ovsize = 0; - if (isset(BASHREMATCH)) - avar="BASH_REMATCH"; + if (isset(BASHREMATCH)) { + svar = NULL; + avar = "BASH_REMATCH"; + } else { + svar = "MATCH"; + avar = "match"; + } switch(id) { case CPCRE_PLAIN: @@ -414,7 +432,7 @@ cond_pcre_match(char **a, int id) break; } else if (r>0) { - zpcre_get_substrings(lhstr_plain, ov, r, NULL, avar, 0, + zpcre_get_substrings(lhstr_plain, ov, r, svar, avar, 0, isset(BASHREMATCH), !isset(BASHREMATCH)); return_value = 1; diff --git a/Src/exec.c b/Src/exec.c index f339dd6d0..cd99733f1 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -41,12 +41,15 @@ enum { ADDVAR_RESTORE = 1 << 2 }; -/* used to suppress ERREXIT and trapping of SIGZERR, SIGEXIT. */ +/* + * used to suppress ERREXIT and trapping of SIGZERR, SIGEXIT. + * Bits from noerrexit_bits. + */ /**/ int noerrexit; -/* used to suppress ERREXIT for one occurrence */ +/* used to suppress ERREXIT or ERRRETURN for one occurrence: 0 or 1 */ /**/ int this_noerrexit; @@ -972,7 +975,7 @@ enum { static void entersubsh(int flags) { - int sig, monitor, job_control_ok; + int i, sig, monitor, job_control_ok; if (!(flags & ESUB_KEEPTRAP)) for (sig = 0; sig < SIGCOUNT; sig++) @@ -1083,6 +1086,14 @@ entersubsh(int flags) opts[MONITOR] = 0; opts[USEZLE] = 0; zleactive = 0; + /* + * If we've saved fd's for later restoring, we're never going + * to restore them now, so just close them. + */ + for (i = 10; i <= max_zsh_fd; i++) { + if (fdtable[i] & FDT_SAVED_MASK) + zclose(i); + } if (flags & ESUB_PGRP) clearjobtab(monitor); get_usage(); @@ -1291,7 +1302,7 @@ execlist(Estate state, int dont_change_job, int exiting) int oerrexit_opt = opts[ERREXIT]; Param pm; opts[ERREXIT] = 0; - noerrexit = 1; + noerrexit = NOERREXIT_EXIT | NOERREXIT_RETURN; if (ltype & Z_SIMPLE) /* skip the line number */ pc2++; pm = setsparam("ZSH_DEBUG_CMD", getpermtext(state->prog, pc2, 0)); @@ -1343,13 +1354,13 @@ execlist(Estate state, int dont_change_job, int exiting) int isend = (WC_SUBLIST_TYPE(code) == WC_SUBLIST_END); next = state->pc + WC_SUBLIST_SKIP(code); if (!oldnoerrexit) - noerrexit = !isend; + noerrexit = isend ? 0 : NOERREXIT_EXIT | NOERREXIT_RETURN; if (WC_SUBLIST_FLAGS(code) & WC_SUBLIST_NOT) { /* suppress errexit for "! this_command" */ if (isend) this_noerrexit = 1; /* suppress errexit for ! <list-of-shell-commands> */ - noerrexit = 1; + noerrexit = NOERREXIT_EXIT | NOERREXIT_RETURN; } switch (WC_SUBLIST_TYPE(code)) { case WC_SUBLIST_END: @@ -1436,11 +1447,11 @@ sublist_done: /* * See hairy code near the end of execif() for the - * following. "noerrexit == 2" only applies until + * following. "noerrexit " only applies until * we hit execcmd on the way down. We're now * on the way back up, so don't restore it. */ - if (oldnoerrexit != 2) + if (!(oldnoerrexit & NOERREXIT_UNTIL_EXEC)) noerrexit = oldnoerrexit; if (sigtrapped[SIGDEBUG] && !isset(DEBUGBEFORECMD) && !donedebug) { @@ -1450,7 +1461,7 @@ sublist_done: */ int oerrexit_opt = opts[ERREXIT]; opts[ERREXIT] = 0; - noerrexit = 1; + noerrexit = NOERREXIT_EXIT | NOERREXIT_RETURN; exiting = donetrap; ret = lastval; dotrap(SIGDEBUG); @@ -1466,16 +1477,19 @@ sublist_done: /* Check whether we are suppressing traps/errexit * * (typically in init scripts) and if we haven't * * already performed them for this sublist. */ - if (!noerrexit && !this_noerrexit && !donetrap && !this_donetrap) { - if (sigtrapped[SIGZERR] && lastval) { + if (!this_noerrexit && !donetrap && !this_donetrap) { + if (sigtrapped[SIGZERR] && lastval && + !(noerrexit & NOERREXIT_EXIT)) { dotrap(SIGZERR); donetrap = 1; } if (lastval) { int errreturn = isset(ERRRETURN) && - (isset(INTERACTIVE) || locallevel || sourcelevel); - int errexit = isset(ERREXIT) || - (isset(ERRRETURN) && !errreturn); + (isset(INTERACTIVE) || locallevel || sourcelevel) && + !(noerrexit & NOERREXIT_RETURN); + int errexit = (isset(ERREXIT) || + (isset(ERRRETURN) && !errreturn)) && + !(noerrexit & NOERREXIT_EXIT); if (errexit) { if (sigtrapped[SIGEXIT]) dotrap(SIGEXIT); @@ -2318,6 +2332,9 @@ addfd(int forked, int *save, struct multio **mfds, int fd1, int fd2, int rflag, return; } save[fd1] = fdN; + DPUTS(fdtable[fdN] != FDT_INTERNAL, + "Saved file descriptor not marked as internal"); + fdtable[fdN] |= FDT_SAVED_MASK; } } } @@ -3008,7 +3025,7 @@ execcmd_exec(Estate state, Execcmd_params eparams, preargs = NULL; /* if we get this far, it is OK to pay attention to lastval again */ - if (noerrexit == 2 && !is_shfunc) + if ((noerrexit & NOERREXIT_UNTIL_EXEC) && !is_shfunc) noerrexit = 0; /* Do prefork substitutions. @@ -3575,7 +3592,8 @@ execcmd_exec(Estate state, Execcmd_params eparams, } if (!bad && fn->fd1 <= max_zsh_fd) { if (fn->fd1 >= 10 && - fdtable[fn->fd1] == FDT_INTERNAL) + (fdtable[fn->fd1] & FDT_TYPE_MASK) == + FDT_INTERNAL) bad = 3; } } @@ -4270,7 +4288,7 @@ closem(int how) for (i = 10; i <= max_zsh_fd; i++) if (fdtable[i] != FDT_UNUSED && - (how == FDT_UNUSED || fdtable[i] == how)) { + (how == FDT_UNUSED || (fdtable[i] & FDT_TYPE_MASK) == how)) { if (i == SHTTY) SHTTY = -1; zclose(i); @@ -5450,6 +5468,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) char saveopts[OPT_SIZE], *oldscriptname = scriptname; char *name = shfunc->node.nam; int flags = shfunc->node.flags, ooflags; + int savnoerrexit; char *fname = dupstring(name); int obreaks, ocontflag, oloops, saveemulation, restore_sticky; Eprog prog; @@ -5472,6 +5491,11 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) trap_return--; oldlastval = lastval; oldnumpipestats = numpipestats; + savnoerrexit = noerrexit; + /* + * Suppression of ERR_RETURN is turned off in function scope. + */ + noerrexit &= ~NOERREXIT_RETURN; if (noreturnval) { /* * Easiest to use the heap here since we're bracketed @@ -5690,6 +5714,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) if (trap_state == TRAP_STATE_PRIMED) trap_return++; ret = lastval; + noerrexit = savnoerrexit; if (noreturnval) { lastval = oldlastval; numpipestats = oldnumpipestats; diff --git a/Src/init.c b/Src/init.c index d8c26aca2..87dd2e26d 100644 --- a/Src/init.c +++ b/Src/init.c @@ -1070,7 +1070,7 @@ setupvals(char *cmd, char *runscript, char *zsh_name) sfcontext = SFC_NONE; trap_return = 0; trap_state = TRAP_STATE_INACTIVE; - noerrexit = -1; + noerrexit = NOERREXIT_EXIT | NOERREXIT_RETURN | NOERREXIT_SIGNAL; nohistsave = 1; dirstack = znewlinklist(); bufstack = znewlinklist(); @@ -1199,7 +1199,7 @@ init_signals(void) void run_init_scripts(void) { - noerrexit = -1; + noerrexit = NOERREXIT_EXIT | NOERREXIT_RETURN | NOERREXIT_SIGNAL; if (EMULATION(EMULATE_KSH|EMULATE_SH)) { if (islogin) @@ -760,7 +760,7 @@ gettok(void) return AMPER; case LX1_BAR: d = hgetc(); - if (d == '|') + if (d == '|' && !incasepat) return DBAR; else if (d == '&') return BARAMP; @@ -1058,7 +1058,7 @@ gettokstr(int c, int sub) if (isset(SHGLOB)) { if (sub || in_brace_param) break; - if (incasepat && !lexbuf.len) + if (incasepat > 0 && !lexbuf.len) return INPAR; if (!isset(KSHGLOB) && lexbuf.len) goto brk; @@ -1859,7 +1859,7 @@ exalias(void) Reswd rw; hwend(); - if (interact && isset(SHINSTDIN) && !strin && !incasepat && + if (interact && isset(SHINSTDIN) && !strin && incasepat <= 0 && tok == STRING && !nocorrect && !(inbufflags & INP_ALIAS) && (isset(CORRECTALL) || (isset(CORRECT) && incmdpos))) spckword(&tokstr, 1, incmdpos, 1); diff --git a/Src/loop.c b/Src/loop.c index f7eae307b..4859c976b 100644 --- a/Src/loop.c +++ b/Src/loop.c @@ -542,7 +542,7 @@ execif(Estate state, int do_exec) end = state->pc + WC_IF_SKIP(code); if (!noerrexit) - noerrexit = 1; + noerrexit = NOERREXIT_EXIT | NOERREXIT_RETURN; while (state->pc < end) { code = *state->pc++; if (wc_code(code) != WC_IF || @@ -567,7 +567,12 @@ execif(Estate state, int do_exec) if (run) { /* we need to ignore lastval until we reach execcmd() */ - noerrexit = olderrexit ? olderrexit : lastval ? 2 : 0; + if (olderrexit) + noerrexit = olderrexit; + else if (lastval) + noerrexit = NOERREXIT_EXIT | NOERREXIT_RETURN | NOERREXIT_UNTIL_EXEC; + else + noerrexit = 0; cmdpush(run == 2 ? CS_ELSE : (s ? CS_ELIFTHEN : CS_IFTHEN)); execlist(state, 1, do_exec); cmdpop(); diff --git a/Src/module.c b/Src/module.c index 21d68b1ac..4ae78310f 100644 --- a/Src/module.c +++ b/Src/module.c @@ -649,11 +649,21 @@ getconddef(int inf, const char *name, int autol) { Conddef p; int f = 1; + char *lookup, *s; + + /* detokenize the Dash to the form encoded in lookup tables */ + lookup = dupstring(name); + if (!lookup) + return NULL; + for (s = lookup; *s != '\0'; s++) { + if (*s == Dash) + *s = '-'; + } do { for (p = condtab; p; p = p->next) { if ((!!inf == !!(p->flags & CONDF_INFIX)) && - !strcmp(name, p->name)) + !strcmp(lookup, p->name)) break; } if (autol && p && p->module) { @@ -664,7 +674,7 @@ getconddef(int inf, const char *name, int autol) if (f) { (void)ensurefeature(p->module, (p->flags & CONDF_INFIX) ? "C:" : "c:", - (p->flags & CONDF_AUTOALL) ? NULL : name); + (p->flags & CONDF_AUTOALL) ? NULL : lookup); f = 0; p = NULL; } else { @@ -674,6 +684,7 @@ getconddef(int inf, const char *name, int autol) } else break; } while (!p); + return p; } diff --git a/Src/parse.c b/Src/parse.c index ba9cd61eb..27052527d 100644 --- a/Src/parse.c +++ b/Src/parse.c @@ -48,7 +48,11 @@ mod_export int incond; /**/ mod_export int inredir; -/* != 0 if we are about to read a case pattern */ +/* + * 1 if we are about to read a case pattern + * -1 if we are not quite sure + * 0 otherwise + */ /**/ int incasepat; @@ -1194,6 +1198,7 @@ par_case(int *cmplx) for (;;) { char *str; + int skip_zshlex; while (tok == SEPER) zshlex(); @@ -1201,11 +1206,17 @@ par_case(int *cmplx) break; if (tok == INPAR) zshlex(); - if (tok != STRING) - YYERRORV(oecused); - if (!strcmp(tokstr, "esac")) - break; - str = dupstring(tokstr); + if (tok == BAR) { + str = dupstring(""); + skip_zshlex = 1; + } else { + if (tok != STRING) + YYERRORV(oecused); + if (!strcmp(tokstr, "esac")) + break; + str = dupstring(tokstr); + skip_zshlex = 0; + } type = WC_CASE_OR; pp = ecadd(0); palts = ecadd(0); @@ -1243,10 +1254,11 @@ par_case(int *cmplx) * this doesn't affect our ability to match a | or ) as * these are valid on command lines. */ - incasepat = 0; + incasepat = -1; incmdpos = 1; - for (;;) { + if (!skip_zshlex) zshlex(); + for (;;) { if (tok == OUTPAR) { ecstr(str); ecadd(ecnpats++); @@ -1302,10 +1314,26 @@ par_case(int *cmplx) } zshlex(); - if (tok != STRING) + switch (tok) { + case STRING: + /* Normal case */ + str = dupstring(tokstr); + zshlex(); + break; + + case OUTPAR: + case BAR: + /* Empty string */ + str = dupstring(""); + break; + + default: + /* Oops. */ YYERRORV(oecused); - str = dupstring(tokstr); + break; + } } + incasepat = 0; par_save_list(cmplx); if (tok == SEMIAMP) type = WC_CASE_AND; diff --git a/Src/signals.c b/Src/signals.c index cad40f4eb..94f379e72 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -652,7 +652,7 @@ zhandler(int sig) case SIGINT: if (!handletrap(SIGINT)) { if ((isset(PRIVILEGED) || isset(RESTRICTED)) && - isset(INTERACTIVE) && noerrexit < 0) + isset(INTERACTIVE) && (noerrexit & NOERREXIT_SIGNAL)) zexit(SIGINT, 1); if (list_pipe || chline || simple_pline) { breaks = loops; @@ -456,6 +456,18 @@ enum { #define FDT_PROC_SUBST 7 #endif +/* + * Mask to get the basic FDT type. + */ +#define FDT_TYPE_MASK 15 + +/* + * Bit flag that fd is saved for later restoration. + * Currently this is only use with FDT_INTERNAL. We use this fact so as + * not to have to mask checks against other types. + */ +#define FDT_SAVED_MASK 16 + /* Flags for input stack */ #define INP_FREE (1<<0) /* current buffer can be free'd */ #define INP_ALIAS (1<<1) /* expanding alias or history */ @@ -2110,6 +2122,17 @@ enum source_return { SOURCE_ERROR = 2 }; +enum noerrexit_bits { + /* Suppress ERR_EXIT and traps: global */ + NOERREXIT_EXIT = 1, + /* Suppress ERR_RETURN: per function call */ + NOERREXIT_RETURN = 2, + /* NOERREXIT only needed on way down */ + NOERREXIT_UNTIL_EXEC = 4, + /* Force exit on SIGINT */ + NOERREXIT_SIGNAL = 8 +}; + /***********************************/ /* Definitions for history control */ /***********************************/ |