From 605a73e415772a1d74cff39212618c8f1d58297b Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Fri, 10 Oct 2014 23:12:57 -0700 Subject: 33429: disallow non-integer values for HISTSIZE and SAVEHIST of "fc -p", and fix crash on zero values for same --- Src/builtin.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'Src/builtin.c') diff --git a/Src/builtin.c b/Src/builtin.c index 4a10c7dd1..5b711edc0 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -1363,10 +1363,19 @@ bin_fc(char *nam, char **argv, Options ops, int func) if (*argv) { hf = *argv++; if (*argv) { - hs = zstrtol(*argv++, NULL, 10); - if (*argv) - shs = zstrtol(*argv++, NULL, 10); - else + char *check; + hs = zstrtol(*argv++, &check, 10); + if (*check) { + zwarnnam("fc", "HISTSIZE must be an integer"); + return 1; + } + if (*argv) { + shs = zstrtol(*argv++, &check, 10); + if (*check) { + zwarnnam("fc", "SAVEHIST must be an integer"); + return 1; + } + } else shs = hs; if (*argv) { zwarnnam("fc", "too many arguments"); -- cgit v1.2.3 From 0ccbc3873f7023a717973e9fe2a4e94317b35ad4 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Sat, 8 Nov 2014 20:49:07 +0000 Subject: Handle -a option to whence in combination with -m. --- ChangeLog | 5 +++++ Src/builtin.c | 46 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 5 deletions(-) (limited to 'Src/builtin.c') diff --git a/ChangeLog b/ChangeLog index 15eda4e10..7c0ffb1c2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2014-11-08 Peter Stephenson + + * 33653: Src/builtin.c: handle -a option to whence in + combination with -m. + 2014-11-08 Barton E. Schaefer * 33648: Completion/Unix/Command/_gpg: complete for gpg2 as well diff --git a/Src/builtin.c b/Src/builtin.c index 5b711edc0..dd22d0984 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -3228,11 +3228,47 @@ bin_whence(char *nam, char **argv, Options ops, int func) scanmatchtable(builtintab, pprog, 1, 0, DISABLED, builtintab->printnode, printflags); } - /* Done search for `internal' commands, if the -p option * - * was not used. Now search the path. */ - cmdnamtab->filltable(cmdnamtab); - scanmatchtable(cmdnamtab, pprog, 1, 0, 0, - cmdnamtab->printnode, printflags); + if (all) { + char **pp, *buf, *fn; + DIR *od; + + pushheap(); + for (pp = path; *pp; pp++) { + if (!**pp) + continue; + od = opendir(*pp); + if (!od) + continue; + + while ((fn = zreaddir(od, 0))) { + if (!pattry(pprog, fn)) + continue; + + buf = zhtricat(*pp, "/", fn); + + if (iscom(buf)) { + if (wd) { + printf("%s: command\n", fn); + } else { + if (v && !csh) + zputs(fn, stdout), fputs(" is ", stdout); + zputs(buf, stdout); + if (OPT_ISSET(ops,'s')) + print_if_link(buf); + fputc('\n', stdout); + } + } + } + closedir(od); + } + popheap(); + } else { + /* Done search for `internal' commands, if the -p option * + * was not used. Now search the path. */ + cmdnamtab->filltable(cmdnamtab); + scanmatchtable(cmdnamtab, pprog, 1, 0, 0, + cmdnamtab->printnode, printflags); + } unqueue_signals(); } -- cgit v1.2.3 From 53344183e1300f3dffeaf602ac4b686ce182e884 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Thu, 13 Nov 2014 09:20:46 -0800 Subject: 33656: different algorithm for "whence -am" to produce results more consistent with "whence -m" This uses the scanmatchtable routine to collect the names that match the input pattern, then uses the original -a path search loop to generate the output, to avoid duplicating test conditions and output formats. --- ChangeLog | 5 ++++ Src/builtin.c | 74 ++++++++++++++++++++++++----------------------------------- 2 files changed, 35 insertions(+), 44 deletions(-) (limited to 'Src/builtin.c') diff --git a/ChangeLog b/ChangeLog index 5609754f5..6b53b1086 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2014-11-13 Barton E. Schaefer + + * 33656: Src/builtin.c: different algorithm for "whence -am" to + produce results more consistent with "whence -m" + 2014-11-13 Oliver Kiddle * 33669: Src/Zle/zle_utils.c, Test/X02zlevi.ztst: allow an empty diff --git a/Src/builtin.c b/Src/builtin.c index dd22d0984..c2af51f2e 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -3154,6 +3154,15 @@ bin_unset(char *name, char **argv, Options ops, int func) /* type, whence, which, command */ +static LinkList matchednodes; + +static void +fetchcmdnamnode(HashNode hn, UNUSED(int printflags)) +{ + Cmdnam cn = (Cmdnam) hn; + addlinknode(matchednodes, cn->node.nam); +} + /**/ int bin_whence(char *nam, char **argv, Options ops, int func) @@ -3165,7 +3174,7 @@ bin_whence(char *nam, char **argv, Options ops, int func) int aliasflags; int csh, all, v, wd; int informed; - char *cnam; + char *cnam, **allmatched = 0; /* Check some option information */ csh = OPT_ISSET(ops,'c'); @@ -3198,6 +3207,10 @@ bin_whence(char *nam, char **argv, Options ops, int func) /* With -m option -- treat arguments as a glob patterns */ if (OPT_ISSET(ops,'m')) { + if (all) { + pushheap(); + matchednodes = newlinklist(); + } for (; *argv; argv++) { /* parse the pattern */ tokenize(*argv); @@ -3228,51 +3241,21 @@ bin_whence(char *nam, char **argv, Options ops, int func) scanmatchtable(builtintab, pprog, 1, 0, DISABLED, builtintab->printnode, printflags); } - if (all) { - char **pp, *buf, *fn; - DIR *od; - - pushheap(); - for (pp = path; *pp; pp++) { - if (!**pp) - continue; - od = opendir(*pp); - if (!od) - continue; - - while ((fn = zreaddir(od, 0))) { - if (!pattry(pprog, fn)) - continue; - - buf = zhtricat(*pp, "/", fn); - - if (iscom(buf)) { - if (wd) { - printf("%s: command\n", fn); - } else { - if (v && !csh) - zputs(fn, stdout), fputs(" is ", stdout); - zputs(buf, stdout); - if (OPT_ISSET(ops,'s')) - print_if_link(buf); - fputc('\n', stdout); - } - } - } - closedir(od); - } - popheap(); - } else { - /* Done search for `internal' commands, if the -p option * - * was not used. Now search the path. */ - cmdnamtab->filltable(cmdnamtab); - scanmatchtable(cmdnamtab, pprog, 1, 0, 0, - cmdnamtab->printnode, printflags); - } + /* Done search for `internal' commands, if the -p option * + * was not used. Now search the path. */ + cmdnamtab->filltable(cmdnamtab); + scanmatchtable(cmdnamtab, pprog, 1, 0, 0, + (all ? fetchcmdnamnode : cmdnamtab->printnode), + printflags); unqueue_signals(); } - return returnval; + if (all) { + allmatched = argv = zlinklist2array(matchednodes); + matchednodes = NULL; + popheap(); + } else + return returnval; } /* Take arguments literally -- do not glob */ @@ -3280,7 +3263,7 @@ bin_whence(char *nam, char **argv, Options ops, int func) for (; *argv; argv++) { informed = 0; - if (!OPT_ISSET(ops,'p')) { + if (!OPT_ISSET(ops,'p') && !allmatched) { char *suf; /* Look for alias */ @@ -3380,6 +3363,9 @@ bin_whence(char *nam, char **argv, Options ops, int func) returnval = 1; } } + if (allmatched) + freearray(allmatched); + unqueue_signals(); return returnval; } -- cgit v1.2.3 From d067ebcacd55472f720b2765ec686a69b25c9a90 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Sun, 7 Dec 2014 16:24:19 +0000 Subject: 33876: etc.: Separate errors and keyboards interrupts Combination of 12 commits from interrupt_abort branch. Basic strategy is to introduce bits to errflag and to set and reset them separately. Remove interrupt status on return to main keymap. Turn off ERRFLAG_INT for always block. Restore bit thereafter: we probably need a new variable in order to allow user interrupts to be reset in the always block. Add TRY_BLOCK_INTERRUPT This works the same as TRY_BLOCK_ERROR, but for a SIGINT, too. Ensure propagation of SIGINT from exited job. If received by foreground job, shell uses ERRFLAG_INT, not ERRFLAG_ERROR, to set the new state. Reset errflag before precmd() Add always block in _main_completion to fix ZLS_COLORS Ensures we get the right state of $ZLS_COLORS at the end of _main_complete even if there's an interrupt. However, the "right state" is a bit messy as it depends on styles. --- ChangeLog | 20 +++++++++++-- Completion/Base/Core/_main_complete | 21 ++++++++------ Doc/Zsh/params.yo | 11 ++++++++ Src/Modules/zpty.c | 2 +- Src/Modules/zutil.c | 8 ++++-- Src/Zle/compcore.c | 2 +- Src/Zle/compctl.c | 10 +++---- Src/Zle/compresult.c | 2 +- Src/Zle/textobjects.c | 2 +- Src/Zle/zle_hist.c | 6 ++-- Src/Zle/zle_keymap.c | 10 +++++++ Src/Zle/zle_main.c | 14 ++++++---- Src/Zle/zle_misc.c | 2 +- Src/Zle/zle_tricky.c | 20 +++++++++++-- Src/Zle/zle_utils.c | 3 +- Src/builtin.c | 22 +++++++-------- Src/exec.c | 56 +++++++++++++++++++++++-------------- Src/glob.c | 12 ++++---- Src/hist.c | 10 ++++--- Src/init.c | 29 ++++++++++++++++--- Src/input.c | 3 +- Src/jobs.c | 23 +++++++++------ Src/lex.c | 5 ++-- Src/loop.c | 28 ++++++++++++++++--- Src/params.c | 13 +++++---- Src/parse.c | 31 ++++++++++---------- Src/prompt.c | 7 +++-- Src/signals.c | 28 ++++++++++++++++--- Src/subst.c | 27 ++++++++++++------ Src/utils.c | 8 +++--- Src/zsh.h | 14 ++++++++++ 31 files changed, 315 insertions(+), 134 deletions(-) (limited to 'Src/builtin.c') diff --git a/ChangeLog b/ChangeLog index 94e28ccb2..e30324894 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2014-12-11 Peter Stephenson + + * 33876: etc.: Completion/Base/Core/_main_complete, + Doc/Zsh/params.yo, Src/Modules/zpty.c, Src/Modules/zutil.c, + Src/Zle/compcore.c, Src/Zle/compctl.c, Src/Zle/compresult.c, + Src/Zle/textobjects.c, Src/Zle/zle_hist.c, Src/Zle/zle_keymap.c, + Src/Zle/zle_main.c, Src/Zle/zle_misc.c, Src/Zle/zle_tricky.c, + Src/Zle/zle_utils.c, Src/builtin.c, Src/exec.c, Src/glob.c, + Src/hist.c, Src/init.c, Src/input.c, Src/jobs.c, Src/lex.c, + Src/loop.c, Src/params.c, Src/parse.c, Src/prompt.c, + Src/signals.c, Src/subst.c, Src/utils.c, Src/zsh.h: Separate + shell errors and user interrupt flags into different bits of + errflag: ERRFLAG_ERROR and ERRFLAG_INT. Various + rationalisations to make keyboard interrupts work smoothly. + Work done on interrupt_abort branch. + 2014-12-10 Mikael Magnusson * 33948: Completion/Unix/Command/_getent, @@ -612,7 +628,7 @@ * 33354: Src/jobs.c, Test/A05execution.ztst: when backgrounding a pipeline, close all pipe descriptors in the parent; add test for both this and 33345+33346 - + 2014-10-03 Bart Schaefer * 33346: Src/parse.c: another bit of the 33345 repair @@ -2083,7 +2099,7 @@ 2013-12-20 Barton E. Schaefer * 32172; Test/A05execution.ztst: regression test for 32171 - + * 32171: Src/exec.c: fix leaked pipe descriptor that could deadlock a pipeline from a complex shell construct or function into an external command diff --git a/Completion/Base/Core/_main_complete b/Completion/Base/Core/_main_complete index bc63e83fb..d6a100777 100644 --- a/Completion/Base/Core/_main_complete +++ b/Completion/Base/Core/_main_complete @@ -43,6 +43,8 @@ local -a precommands typeset -U _lastdescr _comp_ignore _comp_colors +{ + [[ -z "$curcontext" ]] && curcontext=::: zstyle -s ":completion:${curcontext}:" insert-tab tmp || tmp=yes @@ -349,17 +351,20 @@ fi ( "$_comp_force_list" = ?* && nm -ge _comp_force_list ) ]] && compstate[list]="${compstate[list]//messages} force" -if [[ "$compstate[old_list]" = keep ]]; then - if [[ $_saved_colors_set = 1 ]]; then - ZLS_COLORS="$_saved_colors" +} always { + # Stuff we always do to clean up. + if [[ "$compstate[old_list]" = keep ]]; then + if [[ $_saved_colors_set = 1 ]]; then + ZLS_COLORS="$_saved_colors" + else + unset ZLS_COLORS + fi + elif (( $#_comp_colors )); then + ZLS_COLORS="${(j.:.)_comp_colors}" else unset ZLS_COLORS fi -elif (( $#_comp_colors )); then - ZLS_COLORS="${(j.:.)_comp_colors}" -else - unset ZLS_COLORS -fi +} # Now call the post-functions. diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo index 5833d6be9..391a5fb0a 100644 --- a/Doc/Zsh/params.yo +++ b/Doc/Zsh/params.yo @@ -754,6 +754,17 @@ It may be reset, clearing the error condition. See ifzman(em(Complex Commands) in zmanref(zshmisc))\ ifnzman(noderef(Complex Commands)) ) +vindex(TRY_BLOCK_INTERRUPT) +item(tt(TRY_BLOCK_INTERRUPT) )( +This variable works in a similar way to tt(TRY_BLOCK_ERROR), but +represents the status of an interrupt from the signal SIGINT, which +typically comes from the keyboard when the user types tt(^C). If set to +0, any such interrupt will be reset; otherwise, the interrupt is +propagated after the tt(always) block. + +Note that it is possible that an interrupt arrives during the execution +of the tt(always) block; this interrupt is also propagated. +) vindex(TTY) item(tt(TTY))( The name of the tty associated with the shell, if any. diff --git a/Src/Modules/zpty.c b/Src/Modules/zpty.c index 63c79a731..7b6130c6f 100644 --- a/Src/Modules/zpty.c +++ b/Src/Modules/zpty.c @@ -308,7 +308,7 @@ newptycmd(char *nam, char *pname, char **args, int echo, int nblock) prog = parse_string(zjoin(args, ' ', 1), 0); if (!prog) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; scriptname = oscriptname; ineval = oineval; return 1; diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c index 1cca0c4b8..c89495070 100644 --- a/Src/Modules/zutil.c +++ b/Src/Modules/zutil.c @@ -301,7 +301,8 @@ setstypat(Style s, char *pat, Patprog prog, char **vals, int eval) int ef = errflag; eprog = parse_string(zjoin(vals, ' ', 1), 0); - errflag = ef; + /* Keep any user interrupt error status */ + errflag = ef | (errflag & ERRFLAG_INT); if (!eprog) { @@ -394,10 +395,11 @@ evalstyle(Stypat p) unsetparam("reply"); execode(p->eval, 1, 0, "style"); if (errflag) { - errflag = ef; + /* Keep any user interrupt error status */ + errflag = ef | (errflag & ERRFLAG_INT); return NULL; } - errflag = ef; + errflag = ef | (errflag & ERRFLAG_INT); queue_signals(); if ((ret = getaparam("reply"))) diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index 35d410cc6..b0c6e06f8 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -1671,7 +1671,7 @@ set_comp_sep(void) noaliases = ona; strinend(); inpop(); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; noerrs = ne; lexrestore(); wb = owb; diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index 0b7a32445..d15c2d1b0 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -1879,7 +1879,7 @@ ccmakehookfn(UNUSED(Hookdef dummy), struct ccmakedat *dat) if (!m || !(m = m->next)) break; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; } redup(osi, 0); dat->lst = 1; @@ -2121,7 +2121,7 @@ getreal(char *str) if (!errflag && nonempty(l) && ((char *) peekfirst(l)) && ((char *) peekfirst(l))[0]) return dupstring(peekfirst(l)); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; return dupstring(str); } @@ -2599,7 +2599,7 @@ makecomplistlist(Compctl cc, char *s, int incmd, int compadd) makecomplistflags(cc, s, incmd, compadd); /* Reset some information variables for the next try. */ - errflag = 0; + errflag &= ~ERRFLAG_ERROR; offs = oloffs; wb = owb; we = owe; @@ -2847,7 +2847,7 @@ sep_comp_string(char *ss, char *s, int noffs) noaliases = ona; strinend(); inpop(); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; noerrs = ne; lexrestore(); wb = owb; @@ -3725,7 +3725,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) noaliases = ona; strinend(); inpop(); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; lexrestore(); /* Fine, now do full expansion. */ prefork(foo, 0); diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c index fcceb670c..93438a053 100644 --- a/Src/Zle/compresult.c +++ b/Src/Zle/compresult.c @@ -1092,7 +1092,7 @@ do_single(Cmatch m) noerrs = 1; parsestr(p); singsub(&p); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; noerrs = ne; } } else { diff --git a/Src/Zle/textobjects.c b/Src/Zle/textobjects.c index 85d014b27..37d2c0ad9 100644 --- a/Src/Zle/textobjects.c +++ b/Src/Zle/textobjects.c @@ -275,7 +275,7 @@ selectargument(UNUSED(char **args)) noaliases = ona; strinend(); inpop(); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; noerrs = ne; lexrestore(); zlemetacs = ocs; diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c index 9f65994dc..88623bb3c 100644 --- a/Src/Zle/zle_hist.c +++ b/Src/Zle/zle_hist.c @@ -853,8 +853,10 @@ pushlineoredit(char **args) free(zhline); } ret = pushline(args); - if (!isfirstln) - errflag = done = 1; + if (!isfirstln) { + errflag |= ERRFLAG_ERROR; + done = 1; + } clearlist = 1; return ret; } diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index 30d25ebaa..48f210c7e 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -504,6 +504,16 @@ mod_export void selectlocalmap(Keymap m) { localkeymap = m; + if (!m) + { + /* + * No local keymap; so we are returning to the global map. If + * the user ^Ced in the local map, they probably just want to go + * back to normal editing. So remove the interrupt error + * status. + */ + errflag &= ~ERRFLAG_INT; + } } /* Reopen the currently selected keymap, in case it got deleted. This * diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c index caa052b13..a2f48e13a 100644 --- a/Src/Zle/zle_main.c +++ b/Src/Zle/zle_main.c @@ -744,7 +744,7 @@ raw_getbyte(long do_keytmout, char *cptr) } if (errflag) { /* No sensible way of handling errors here */ - errflag = 0; + errflag &= ~ERRFLAG_ERROR; /* * Paranoia: don't run the hooks again this * time. @@ -882,7 +882,7 @@ getbyte(long do_keytmout, int *timeout) die = 0; if (!errflag && !retflag && !breaks && !exit_pending) continue; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; breaks = obreaks; errno = old_errno; return lastchar = EOF; @@ -1075,7 +1075,7 @@ zlecore(void) DECCS(); handleundo(); } else { - errflag = 1; + errflag |= ERRFLAG_ERROR; break; } #ifdef HAVE_POLL @@ -1233,6 +1233,10 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish) zleactive = 1; resetneeded = 1; + /* + * Start of the main zle read. + * Fully reset error conditions, including user interrupt. + */ errflag = retflag = 0; lastcol = -1; initmodifier(&zmod); @@ -1658,7 +1662,7 @@ bin_vared(char *name, char **args, Options ops, UNUSED(int func)) } if (!t || errflag) { /* error in editing */ - errflag = 0; + errflag &= ~ERRFLAG_ERROR; breaks = obreaks; if (t) zsfree(t); @@ -1778,7 +1782,7 @@ recursiveedit(UNUSED(char **args)) zrefresh(); zlecore(); - locerror = errflag; + locerror = errflag ? 1 : 0; errflag = done = eofsent = 0; return locerror; diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c index d432acf7b..23286fc20 100644 --- a/Src/Zle/zle_misc.c +++ b/Src/Zle/zle_misc.c @@ -1041,7 +1041,7 @@ copyprevshellword(UNUSED(char **args)) int sendbreak(UNUSED(char **args)) { - errflag = 1; + errflag |= ERRFLAG_ERROR; return 1; } diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index b15d91c8e..864f804b7 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -829,7 +829,7 @@ docomplete(int lst) if (olst == COMP_EXPAND_COMPLETE && !strcmp(ol, zlemetaline)) { zlemetacs = ocs; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; if (!compfunc) { char *p; @@ -877,6 +877,19 @@ docomplete(int lst) active = 0; makecommaspecial(0); + + /* + * As a special case, we reset user interrupts here. + * That's because completion is an intensive piece of + * computation that the user might want to interrupt separately + * from anything else going on. If they do, they probably + * want to keep the line edit buffer intact. + * + * There's a race here that the user might hit ^C just + * after completion exited anyway, but that's inevitable. + */ + errflag &= ~ERRFLAG_INT; + return dat[1]; } @@ -1394,7 +1407,8 @@ get_comp_string(void) } strinend(); inpop(); - errflag = lexflags = 0; + lexflags = 0; + errflag &= ~ERRFLAG_ERROR; if (parbegin != -1) { /* We are in command or process substitution if we are not in * a $((...)). */ @@ -2917,7 +2931,7 @@ getcurcmd(void) popheap(); strinend(); inpop(); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; unmetafy_line(); lexrestore(); diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c index 08a32c30e..de91182b5 100644 --- a/Src/Zle/zle_utils.c +++ b/Src/Zle/zle_utils.c @@ -1715,7 +1715,8 @@ zlecallhook(char *name, char *arg) execzlefunc(thingy, args, 1); unrefthingy(thingy); - errflag = saverrflag; + /* Retain any user interrupt error status */ + errflag = saverrflag | (errflag & ERRFLAG_INT); retflag = savretflag; } diff --git a/Src/builtin.c b/Src/builtin.c index c2af51f2e..ad3a1925f 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -422,7 +422,7 @@ execbuiltin(LinkList args, Builtin bn) argc -= argv - argarr; if (errflag) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; return 1; } @@ -3136,7 +3136,7 @@ bin_unset(char *name, char **argv, Options ops, int func) } } returnval = errflag; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; } else { zerrnam(name, "%s: invalid element for unset", s); returnval = 1; @@ -4242,7 +4242,7 @@ bin_print(char *name, char **args, Options ops, int func) if (*argp) { width = (int)mathevali(*argp++); if (errflag) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; ret = 1; } } @@ -4272,7 +4272,7 @@ bin_print(char *name, char **args, Options ops, int func) if (*argp) { prec = (int)mathevali(*argp++); if (errflag) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; ret = 1; } } @@ -4452,7 +4452,7 @@ bin_print(char *name, char **args, Options ops, int func) zlongval = (curarg) ? mathevali(curarg) : 0; if (errflag) { zlongval = 0; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; ret = 1; } print_val(zlongval) @@ -4481,7 +4481,7 @@ bin_print(char *name, char **args, Options ops, int func) } else doubleval = 0; if (errflag) { doubleval = 0; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; ret = 1; } print_val(doubleval) @@ -4494,7 +4494,7 @@ bin_print(char *name, char **args, Options ops, int func) zulongval = (curarg) ? mathevali(curarg) : 0; if (errflag) { zulongval = 0; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; ret = 1; } print_val(zulongval) @@ -4871,7 +4871,7 @@ zexit(int val, int from_where) in_exit = -1; /* * We want to do all remaining processing regardless of preceding - * errors. + * errors, even user interrupts. */ errflag = 0; @@ -5074,7 +5074,7 @@ eval(char **argv) if (fpushed) funcstack = funcstack->prev; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; scriptname = oscriptname; ineval = oineval; @@ -6101,7 +6101,7 @@ bin_test(char *name, char **argv, UNUSED(Options ops), int func) condlex = zshlex; if (errflag) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; lexrestore(); return 1; } @@ -6278,7 +6278,7 @@ bin_let(UNUSED(char *name), char **argv, UNUSED(Options ops), UNUSED(int func)) while (*argv) val = matheval(*argv++); /* Errors in math evaluation in let are non-fatal. */ - errflag = 0; + errflag &= ~ERRFLAG_ERROR; /* should test for fabs(val.u.d) < epsilon? */ return (val.type == MN_INTEGER) ? val.u.l == 0 : val.u.d == 0.0; } diff --git a/Src/exec.c b/Src/exec.c index a5f877191..6a7dbb1e1 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -59,7 +59,7 @@ mod_export int noerrs; /**/ int nohistsave; -/* error/break flag */ +/* error flag: bits from enum errflag_bits */ /**/ mod_export int errflag; @@ -1601,7 +1601,8 @@ execpline(Estate state, wordcode slcode, int how, int last1) (killpg(jobtab[list_pipe_job].gleader, 0) == -1 ? 2 : 1); list_pipe_pid = pid; list_pipe_start = bgtime; - nowait = errflag = 1; + nowait = 1; + errflag |= ERRFLAG_ERROR; breaks = loops; close(synch[1]); read_loop(synch[0], &dummy, 1); @@ -1634,7 +1635,10 @@ execpline(Estate state, wordcode slcode, int how, int last1) list_pipe_child = 1; opts[INTERACTIVE] = 0; if (errbrk_saved) { - errflag = prev_errflag; + /* + * Keep any user interrupt bit in errflag. + */ + errflag = prev_errflag | (errflag & ERRFLAG_INT); breaks = prev_breaks; } break; @@ -1719,12 +1723,14 @@ execpline2(Estate state, wordcode pcode, if (pipe(synch) < 0) { zerr("pipe failed: %e", errno); - lastval = errflag = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; return; } else if ((pid = zfork(&bgtime)) == -1) { close(synch[0]); close(synch[1]); - lastval = errflag = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; return; } else if (pid) { char dummy, *text; @@ -2560,7 +2566,8 @@ execcmd(Estate state, int input, int output, int how, int last1) while (next && *next == '-' && strlen(next) >= 2) { if (!firstnode(args)) { zerr("exec requires a command to execute"); - errflag = lastval = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; goto done; } uremnode(args, firstnode(args)); @@ -2577,12 +2584,14 @@ execcmd(Estate state, int input, int output, int how, int last1) } else { if (!firstnode(args)) { zerr("exec requires a command to execute"); - errflag = lastval = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; goto done; } if (!nextnode(firstnode(args))) { zerr("exec flag -a requires a parameter"); - errflag = lastval = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; goto done; } exec_argv0 = (char *) @@ -2598,7 +2607,8 @@ execcmd(Estate state, int input, int output, int how, int last1) break; default: zerr("unknown exec flag -%c", *cmdopt); - errflag = lastval = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; return; } } @@ -2661,7 +2671,8 @@ execcmd(Estate state, int input, int output, int how, int last1) } else if (!nullcmd || !*nullcmd || opts[CSHNULLCMD] || (cflags & BINF_PREFIX)) { zerr("redirection with no command"); - errflag = lastval = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; return; } else if (!nullcmd || !*nullcmd || opts[SHNULLCMD]) { if (!args) @@ -2691,7 +2702,7 @@ execcmd(Estate state, int input, int output, int how, int last1) if (varspc) addvars(state, varspc, 0); if (errflag) - lastval = errflag; + lastval = 1; else lastval = cmdoutval; if (isset(XTRACE)) { @@ -2795,7 +2806,7 @@ execcmd(Estate state, int input, int output, int how, int last1) } } if (!nextnode(firstnode(args))) - errflag = 1; + errflag |= ERRFLAG_ERROR; } if (type == WC_FUNCDEF) { @@ -2940,7 +2951,8 @@ execcmd(Estate state, int input, int output, int how, int last1) } else if ((pid = zfork(&bgtime)) == -1) { close(synch[0]); close(synch[1]); - lastval = errflag = 1; + lastval = 1; + errflag |= ERRFLAG_ERROR; goto fatal; } if (pid) { @@ -3529,7 +3541,7 @@ execcmd(Estate state, int input, int output, int how, int last1) else exit(1); } - errflag = 1; + errflag |= ERRFLAG_ERROR; } } if (newxtrerr) { @@ -3759,8 +3771,10 @@ gethere(char **strp, int typ) parsestr(buf); - if (!errflag) - errflag = ef; + if (!errflag) { + /* Retain any user interrupt error */ + errflag = ef | (errflag & ERRFLAG_INT); + } } s = dupstring(buf); zfree(buf, bsiz); @@ -3854,7 +3868,7 @@ getoutput(char *cmd, int qt) return readoutput(stream, qt); } if (mpipe(pipes) < 0) { - errflag = 1; + errflag |= ERRFLAG_ERROR; cmdoutpid = 0; return NULL; } @@ -3864,7 +3878,7 @@ getoutput(char *cmd, int qt) /* fork error */ zclose(pipes[0]); zclose(pipes[1]); - errflag = 1; + errflag |= ERRFLAG_ERROR; cmdoutpid = 0; child_unblock(); return NULL; @@ -4274,7 +4288,7 @@ execcond(Estate state, UNUSED(int do_exec)) * into a shell error. */ if (stat == 2) - errflag = 1; + errflag |= ERRFLAG_ERROR; cmdpop(); if (isset(XTRACE)) { fprintf(xtrerr, " ]]\n"); @@ -4314,7 +4328,7 @@ execarith(Estate state, UNUSED(int do_exec)) fflush(xtrerr); } if (errflag) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; return 2; } /* should test for fabs(val.u.d) < epsilon? */ @@ -4932,7 +4946,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) (name = fname)))) { zwarn("%s: function not defined by file", name); if (noreturnval) - errflag = 1; + errflag |= ERRFLAG_ERROR; else lastval = 1; goto doneshfunc; diff --git a/Src/glob.c b/Src/glob.c index b3903f2ff..82f8d626c 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -682,7 +682,7 @@ parsecomplist(char *instr) /* Now get the next path component if there is one. */ l1 = (Complist) zhalloc(sizeof *l1); if ((l1->next = parsecomplist(instr)) == NULL) { - errflag = 1; + errflag |= ERRFLAG_ERROR; return NULL; } l1->pat = patcompile(NULL, compflags | PAT_ANY, NULL); @@ -728,7 +728,7 @@ parsecomplist(char *instr) return (ef && !l1->next) ? NULL : l1; } } - errflag = 1; + errflag |= ERRFLAG_ERROR; return NULL; } @@ -1790,7 +1790,7 @@ zglob(LinkList list, LinkNode np, int nountok) insertlinknode(list, node, ostr); return; } - errflag = 0; + errflag &= ~ERRFLAG_ERROR; zerr("bad pattern: %s", ostr); return; } @@ -1873,7 +1873,8 @@ zglob(LinkList list, LinkNode np, int nountok) tmpptr->sortstrs[iexec] = tmpptr->name; } - errflag = ef; + /* Retain any user interrupt error status */ + errflag = ef | (errflag & ERRFLAG_INT); lastval = lv; } else { /* Failed, let's be safe */ @@ -3733,7 +3734,8 @@ qualsheval(char *name, UNUSED(struct stat *buf), UNUSED(off_t days), char *str) execode(prog, 1, 0, "globqual"); ret = lastval; - errflag = ef; + /* Retain any user interrupt error status */ + errflag = ef | (errflag & ERRFLAG_INT); lastval = lv; if (!(inserts = getaparam("reply")) && diff --git a/Src/hist.c b/Src/hist.c index 7fe843a4a..a0061707c 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -287,7 +287,8 @@ ihgetc(void) c = histsubchar(c); if (c < 0) { /* bad expansion */ - errflag = lexstop = 1; + lexstop = 1; + errflag |= ERRFLAG_ERROR; return ' '; } } @@ -721,7 +722,7 @@ histsubchar(int c) noerrs = 1; parse_subst_string(sline); noerrs = one; - errflag = oef; + errflag = oef | (errflag & ERRFLAG_INT); remnulargs(sline); untokenize(sline); } @@ -880,7 +881,8 @@ hbegin(int dohist) char *hf; isfirstln = isfirstch = 1; - errflag = histdone = 0; + errflag &= ~ERRFLAG_ERROR; + histdone = 0; if (!dohist) stophist = 2; else if (dohist != 2) @@ -3182,7 +3184,7 @@ bufferwords(LinkList list, char *buf, int *index, int flags) noaliases = ona; strinend(); inpop(); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; nocomments = onc; noerrs = ne; lexrestore(); diff --git a/Src/init.c b/Src/init.c index 655166135..305908724 100644 --- a/Src/init.c +++ b/Src/init.c @@ -118,11 +118,24 @@ loop(int toplevel, int justonce) if (interact && toplevel) { int hstop = stophist; stophist = 3; + /* + * Reset all errors including the interrupt error status + * immediately, so preprompt runs regardless of what + * just happened. We'll reset again below as a + * precaution to ensure we get back to the command line + * no matter what. + */ + errflag = 0; preprompt(); if (stophist != 3) hbegin(1); else stophist = hstop; + /* + * Reset all errors, including user interupts. + * This is what allows ^C in an interactive shell + * to return us to the command line. + */ errflag = 0; } } @@ -178,7 +191,15 @@ loop(int toplevel, int justonce) /* The only permanent storage is from getpermtext() */ zsfree(cmdstr); - errflag = 0; + /* + * Note this does *not* remove a user interrupt error + * condition, even though we're at the top level loop: + * that would be inconsistent with the case where + * we didn't execute a preexec function. This is + * an implementation detail that an interrupting user + * does't care about. + */ + errflag &= ~ERRFLAG_ERROR; } if (stopmsg) /* unset 'you have stopped jobs' flag */ stopmsg--; @@ -689,7 +710,7 @@ init_term(void) { if (isset(INTERACTIVE)) zerr("can't find terminal definition for %s", term); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; termflags |= TERM_BAD; return 0; } else { @@ -1336,7 +1357,7 @@ source(char *s) if (prog) { pushheap(); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; execode(prog, 1, 0, "filecode"); popheap(); if (errflag) @@ -1379,7 +1400,7 @@ source(char *s) lineno = oldlineno; /* our current lineno */ loops = oloops; /* the # of nested loops we are in */ dosetopt(SHINSTDIN, oldshst, 1, opts); /* SHINSTDIN option */ - errflag = 0; + errflag &= ~ERRFLAG_ERROR; if (!exit_pending) retflag = 0; scriptname = old_scriptname; diff --git a/Src/input.c b/Src/input.c index 4ac7e6ec8..9552331a9 100644 --- a/Src/input.c +++ b/Src/input.c @@ -291,7 +291,8 @@ inputline(void) } if (errflag) { free(ingetcline); - return lexstop = errflag = 1; + errflag |= ERRFLAG_ERROR; + return lexstop = 1; } if (isset(VERBOSE)) { /* Output the whole line read so far. */ diff --git a/Src/jobs.c b/Src/jobs.c index 6663a40a6..a668b07e6 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -509,7 +509,7 @@ update_job(Job jn) prev_errflag = errflag; } breaks = loops; - errflag = 1; + errflag |= ERRFLAG_INT; inerrflush(); } } else { @@ -526,7 +526,7 @@ update_job(Job jn) prev_errflag = errflag; } breaks = loops; - errflag = 1; + errflag |= ERRFLAG_INT; inerrflush(); } if (somestopped && jn->stat & STAT_SUPERJOB) @@ -581,7 +581,7 @@ update_job(Job jn) breaks = loops; } else { breaks = loops; - errflag = 1; + errflag |= ERRFLAG_INT; } check_cursh_sig(sig); } @@ -1444,12 +1444,19 @@ zwaitjob(int job, int wait_cmd) restore_queue_signals(q); return 128 + last_signal; } - /* Commenting this out makes ^C-ing a job started by a function - stop the whole function again. But I guess it will stop - something else from working properly, we have to find out - what this might be. --oberon + /* Commenting this out makes ^C-ing a job started by a function + stop the whole function again. But I guess it will stop + something else from working properly, we have to find out + what this might be. --oberon + + When attempting to separate errors and interrupts, we + assumed because of the previous comment it would be OK + to remove ERRFLAG_ERROR and leave ERRFLAG_INT set, since + that's the one related to ^C. But that doesn't work. + There's something more here we don't understand. --pws + + errflag = 0; */ - errflag = 0; */ if (subsh) { killjb(jn, SIGCONT); jn->stat &= ~STAT_STOPPED; diff --git a/Src/lex.c b/Src/lex.c index b2a05448c..4addf8033 100644 --- a/Src/lex.c +++ b/Src/lex.c @@ -385,7 +385,7 @@ lexrestore(void) ecnfunc = ln->ecnfunc; hlinesz = ln->hlinesz; toklineno = ln->toklineno; - errflag = 0; + errflag &= ~ERRFLAG_ERROR; free(ln); unqueue_signals(); @@ -1737,7 +1737,8 @@ parse_subst_string(char *s) inpop(); DPUTS(cmdsp, "BUG: parse_subst_string: cmdstack not empty."); lexrestore(); - errflag = err; + /* Keep any interrupt error status */ + errflag = err | (errflag & ERRFLAG_INT); if (ctok == LEXERR) { untokenize(s); return 1; diff --git a/Src/loop.c b/Src/loop.c index 82d2fe31a..8bb1ec9dd 100644 --- a/Src/loop.c +++ b/Src/loop.c @@ -259,7 +259,8 @@ execselect(Estate state, UNUSED(int do_exec)) 0, ZLCON_SELECT); if (errflag) str = NULL; - errflag = oef; + /* Keep any user interrupt error status */ + errflag = oef | (errflag & ERRFLAG_INT); } else { str = promptexpand(prompt3, 0, NULL, NULL, NULL); zputs(str, stderr); @@ -632,6 +633,14 @@ execcase(Estate state, int do_exec) zlong try_errflag = -1; +/** + * Corresponding interrupt error status form `try' block. + */ + +/**/ +zlong +try_interrupt = -1; + /**/ zlong try_tryflag = 0; @@ -643,7 +652,7 @@ exectry(Estate state, int do_exec) Wordcode end, always; int endval; int save_retflag, save_breaks, save_contflag; - zlong save_try_errflag, save_try_tryflag; + zlong save_try_errflag, save_try_tryflag, save_try_interrupt; end = state->pc + WC_TRY_SKIP(state->pc[-1]); always = state->pc + 1 + WC_TRY_SKIP(*state->pc); @@ -670,7 +679,10 @@ exectry(Estate state, int do_exec) /* The always clause. */ save_try_errflag = try_errflag; - try_errflag = (zlong)errflag; + save_try_interrupt = try_interrupt; + try_errflag = (zlong)(errflag & ERRFLAG_ERROR); + try_interrupt = (zlong)((errflag & ERRFLAG_INT) ? 1 : 0); + /* We need to reset all errors to allow the block to execute */ errflag = 0; save_retflag = retflag; retflag = 0; @@ -682,8 +694,16 @@ exectry(Estate state, int do_exec) state->pc = always; execlist(state, 1, do_exec); - errflag = try_errflag ? 1 : 0; + if (try_errflag) + errflag |= ERRFLAG_ERROR; + else + errflag &= ~ERRFLAG_ERROR; + if (try_interrupt) + errflag |= ERRFLAG_INT; + else + errflag &= ~ERRFLAG_INT; try_errflag = save_try_errflag; + try_interrupt = save_try_interrupt; if (!retflag) retflag = save_retflag; if (!breaks) diff --git a/Src/params.c b/Src/params.c index 61edc5d08..79088d162 100644 --- a/Src/params.c +++ b/Src/params.c @@ -331,6 +331,7 @@ IPDEF5("SHLVL", &shlvl, varinteger_gsu), #define IPDEF6(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL|PM_DONTIMPORT},BR((void *)B),GSU(F),10,0,NULL,NULL,NULL,0} IPDEF6("OPTIND", &zoptind, varinteger_gsu), IPDEF6("TRY_BLOCK_ERROR", &try_errflag, varinteger_gsu), +IPDEF6("TRY_BLOCK_INTERRUPT", &try_interrupt, varinteger_gsu), #define IPDEF7(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL},BR((void *)B),GSU(varscalar_gsu),0,0,NULL,NULL,NULL,0} #define IPDEF7U(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL|PM_UNSET},BR((void *)B),GSU(varscalar_gsu),0,0,NULL,NULL,NULL,0} @@ -2654,7 +2655,7 @@ assignsparam(char *s, char *val, int flags) if (!isident(s)) { zerr("not an identifier: %s", s); zsfree(val); - errflag = 1; + errflag |= ERRFLAG_ERROR; return NULL; } queue_signals(); @@ -2783,7 +2784,7 @@ assignaparam(char *s, char **val, int flags) if (!isident(s)) { zerr("not an identifier: %s", s); freearray(val); - errflag = 1; + errflag |= ERRFLAG_ERROR; return NULL; } queue_signals(); @@ -2799,7 +2800,7 @@ assignaparam(char *s, char **val, int flags) zerr("%s: attempt to set slice of associative array", v->pm->node.nam); freearray(val); - errflag = 1; + errflag |= ERRFLAG_ERROR; return NULL; } v = NULL; @@ -2870,13 +2871,13 @@ sethparam(char *s, char **val) if (!isident(s)) { zerr("not an identifier: %s", s); freearray(val); - errflag = 1; + errflag |= ERRFLAG_ERROR; return NULL; } if (strchr(s, '[')) { freearray(val); zerr("nested associative arrays not yet supported"); - errflag = 1; + errflag |= ERRFLAG_ERROR; return NULL; } if (unset(EXECOPT)) @@ -2916,7 +2917,7 @@ setnparam(char *s, mnumber val) if (!isident(s)) { zerr("not an identifier: %s", s); - errflag = 1; + errflag |= ERRFLAG_ERROR; return NULL; } if (unset(EXECOPT)) diff --git a/Src/parse.c b/Src/parse.c index 4ceeb4eaf..c1709e03a 100644 --- a/Src/parse.c +++ b/Src/parse.c @@ -71,13 +71,14 @@ struct heredocs *hdocs; #define YYERROR(O) { tok = LEXERR; ecused = (O); return 0; } #define YYERRORV(O) { tok = LEXERR; ecused = (O); return; } -#define COND_ERROR(X,Y) do { \ - zwarn(X,Y); \ - herrflush(); \ - if (noerrs != 2) \ - errflag = 1; \ - YYERROR(ecused) \ -} while(0) +#define COND_ERROR(X,Y) \ + do { \ + zwarn(X,Y); \ + herrflush(); \ + if (noerrs != 2) \ + errflag |= ERRFLAG_ERROR; \ + YYERROR(ecused) \ + } while(0) /* @@ -506,7 +507,7 @@ par_event(void) yyerror(1); herrflush(); if (noerrs != 2) - errflag = 1; + errflag |= ERRFLAG_ERROR; ecused--; return 0; } else { @@ -2339,7 +2340,7 @@ yyerror(int noerr) zwarn("parse error"); } if (!noerr && noerrs != 2) - errflag = 1; + errflag |= ERRFLAG_ERROR; } /* @@ -3031,7 +3032,7 @@ build_dump(char *nam, char *dump, char **files, int ali, int map, int flags) file = metafy(file, flen, META_REALLOC); if (!(prog = parse_string(file, 1)) || errflag) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; close(dfd); zfree(file, flen); zwarnnam(nam, "can't read file: %s", *files); @@ -3141,7 +3142,7 @@ build_cur_dump(char *nam, char *dump, char **names, int match, int map, for (hn = shfunctab->nodes[i]; hn; hn = hn->next) if (cur_add_func(nam, (Shfunc) hn, lnames, progs, &hlen, &tlen, what)) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; close(dfd); unlink(dump); return 1; @@ -3166,7 +3167,7 @@ build_cur_dump(char *nam, char *dump, char **names, int match, int map, pattry(pprog, hn->nam) && cur_add_func(nam, (Shfunc) hn, lnames, progs, &hlen, &tlen, what)) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; close(dfd); unlink(dump); return 1; @@ -3177,13 +3178,13 @@ build_cur_dump(char *nam, char *dump, char **names, int match, int map, if (errflag || !(shf = (Shfunc) shfunctab->getnode(shfunctab, *names))) { zwarnnam(nam, "unknown function: %s", *names); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; close(dfd); unlink(dump); return 1; } if (cur_add_func(nam, shf, lnames, progs, &hlen, &tlen, what)) { - errflag = 0; + errflag &= ~ERRFLAG_ERROR; close(dfd); unlink(dump); return 1; @@ -3192,7 +3193,7 @@ build_cur_dump(char *nam, char *dump, char **names, int match, int map, } if (empty(progs)) { zwarnnam(nam, "no functions"); - errflag = 0; + errflag &= ~ERRFLAG_ERROR; close(dfd); unlink(dump); return 1; diff --git a/Src/prompt.c b/Src/prompt.c index 0cc9ef917..3552575f3 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -192,8 +192,11 @@ promptexpand(char *s, int ns, char *rs, char *Rs, unsigned int *txtchangep) if (*s == Nularg && s[1] == '\0') *s = '\0'; - /* Ignore errors and status change in prompt substitution */ - errflag = olderr; + /* + * Ignore errors and status change in prompt substitution. + * However, keep any user interrupt error that occurred. + */ + errflag = olderr | (errflag & ERRFLAG_INT); lastval = oldval; } diff --git a/Src/signals.c b/Src/signals.c index e72850516..899f1217b 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -619,7 +619,7 @@ zhandler(int sig) zexit(SIGINT, 1); if (list_pipe || chline || simple_pline) { breaks = loops; - errflag = 1; + errflag |= ERRFLAG_INT; inerrflush(); check_cursh_sig(SIGINT); } @@ -640,6 +640,11 @@ zhandler(int sig) if (idle >= 0 && idle < tmout) alarm(tmout - idle); else { + /* + * We want to exit now. + * Cancel all errors, including a user interrupt + * which is now redundant. + */ errflag = noerrs = 0; zwarn("timeout"); stopmsg = 1; @@ -1267,7 +1272,18 @@ dotrapargs(int sig, int *sigtr, void *sigfn) !(isfunc && new_trap_return == 0)) { if (isfunc) { breaks = loops; - errflag = 1; + /* + * For SIGINT we behave the same as the default behaviour + * i.e. we set the error bit indicating an interrupt. + * We do this with SIGQUIT, too, even though we don't + * handle SIGQUIT by default. That's to try to make + * it behave a bit more like its normal behaviour when + * the trap handler has told us that's what it wants. + */ + if (sig == SIGINT || sig == SIGQUIT) + errflag |= ERRFLAG_INT; + else + errflag |= ERRFLAG_ERROR; } lastval = new_trap_return; /* return triggered */ @@ -1282,8 +1298,12 @@ dotrapargs(int sig, int *sigtr, void *sigfn) */ lastval = olastval; } - if (try_tryflag) - errflag = traperr; + if (try_tryflag) { + if (traperr) + errflag |= ERRFLAG_ERROR; + else + errflag &= ~ERRFLAG_ERROR; + } breaks += obreaks; /* return not triggered: restore old flag */ retflag = oretflag; diff --git a/Src/subst.c b/Src/subst.c index 61aa1c136..43932c256 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -2822,7 +2822,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) haserr = parse_subst_string(s); noerrs = one; if (!quoteerr) { - errflag = oef; + /* Retain user interrupt error status */ + errflag = oef | (errflag & ERRFLAG_INT); if (haserr) shtokenize(s); } else if (haserr || errflag) { @@ -3249,8 +3250,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) haserr = 1; } noerrs = one; - if (!quoteerr) - errflag = oef; + if (!quoteerr) { + /* Retain user interrupt error status */ + errflag = oef | (errflag & ERRFLAG_INT); + } if (haserr || errflag) return NULL; } @@ -3483,8 +3486,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) untokenize(*ap); } noerrs = one; - if (!quoteerr) - errflag = oef; + if (!quoteerr) { + /* Retain any user interrupt error status */ + errflag = oef | (errflag & ERRFLAG_INT); + } else if (haserr || errflag) { zerr("parse error in parameter value"); return NULL; @@ -3516,8 +3521,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) noerrs = 1; haserr = parse_subst_string(val); noerrs = one; - if (!quoteerr) - errflag = oef; + if (!quoteerr) { + /* Retain any user interrupt error status */ + errflag = oef | (errflag & ERRFLAG_INT); + } else if (haserr || errflag) { zerr("parse error in parameter value"); return NULL; @@ -4086,7 +4093,8 @@ modify(char **str, char **ptr) noerrs = 1; parse_subst_string(copy); noerrs = one; - errflag = oef; + /* Retain any user interrupt error status */ + errflag = oef | (errflag & ERRFLAG_INT); remnulargs(copy); untokenize(copy); } @@ -4161,7 +4169,8 @@ modify(char **str, char **ptr) noerrs = 1; parse_subst_string(*str); noerrs = one; - errflag = oef; + /* Retain any user interrupt error status */ + errflag = oef | (errflag & ERRFLAG_INT); remnulargs(*str); untokenize(*str); } diff --git a/Src/utils.c b/Src/utils.c index ab3d3da93..893a8ca02 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -153,7 +153,7 @@ VA_DCL if (errflag || noerrs) { if (noerrs < 2) - errflag = 1; + errflag |= ERRFLAG_ERROR; return; } @@ -161,7 +161,7 @@ VA_DCL VA_GET_ARG(ap, fmt, const char *); zwarning(NULL, fmt, ap); va_end(ap); - errflag = 1; + errflag |= ERRFLAG_ERROR; } /**/ @@ -181,7 +181,7 @@ VA_DCL VA_GET_ARG(ap, fmt, const char *); zwarning(cmd, fmt, ap); va_end(ap); - errflag = 1; + errflag |= ERRFLAG_ERROR; } /**/ @@ -330,7 +330,7 @@ zerrmsg(FILE *file, const char *fmt, va_list ap) num = va_arg(ap, int); if (num == EINTR) { fputs("interrupt\n", file); - errflag = 1; + errflag |= ERRFLAG_ERROR; return; } errmsg = strerror(num); diff --git a/Src/zsh.h b/Src/zsh.h index 031deaf3f..b366e0ff4 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -2623,6 +2623,20 @@ enum trap_state { #define IN_EVAL_TRAP() \ (intrap && !trapisfunc && traplocallevel == locallevel) +/* + * Bits in the errflag variable. + */ +enum errflag_bits { + /* + * Standard internal error bit. + */ + ERRFLAG_ERROR = 1, + /* + * User interrupt. + */ + ERRFLAG_INT = 2 +}; + /***********/ /* Sorting */ /***********/ -- cgit v1.2.3 From e12b51508277c30530dea85965862ade4ce865d4 Mon Sep 17 00:00:00 2001 From: Jun Kuriyama Date: Tue, 16 Dec 2014 23:40:32 -0800 Subject: 33984: bin_dirs() should use zputs() to print metafied directory names --- ChangeLog | 5 ++++- Src/builtin.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'Src/builtin.c') diff --git a/ChangeLog b/ChangeLog index 3225513a5..522ae9768 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,7 @@ -2014-12-16 Barton E. Schaefer +2014-12-16 Barton E. Schaefer + + * Jun Kuriyama: 33984: Src/builtin.c: bin_dirs() should use + zputs() to print metafied directory names * Chirantan Ekbote: 33982: Src/jobs.c: minimal support for pid namespaces by recognizing that GETPGRP() may return 0 diff --git a/Src/builtin.c b/Src/builtin.c index ad3a1925f..264169cb4 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -719,7 +719,7 @@ bin_dirs(UNUSED(char *name), char **argv, Options ops, UNUSED(int func)) for (node = firstnode(dirstack); node; incnode(node)) { printf(fmt, pos++); if (OPT_ISSET(ops,'l')) - fputs(getdata(node), stdout); + zputs(getdata(node), stdout); else fprintdir(getdata(node), stdout); -- cgit v1.2.3 From 33d1439fdbf56ec100dbddfa9f7472a0da59d183 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Fri, 2 Jan 2015 21:32:51 +0000 Subject: users/19667: whence -S shows intermediate steps in symlink expansion --- ChangeLog | 3 +++ Doc/Zsh/builtins.yo | 9 +++++-- Src/builtin.c | 12 +++++----- Src/utils.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 76 insertions(+), 15 deletions(-) (limited to 'Src/builtin.c') diff --git a/ChangeLog b/ChangeLog index 4e125d1de..ac957d1df 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2015-01-02 Peter Stephenson + * users/19667: Doc/Zsh/builtins.yo, Src/builtin.c, Src/utils.c: + whence -S shows intermediate steps in symlink expansion. + * 34077: Test/A07control.ztst: add some further tests for return status from "for" loops. diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo index 38788d3c4..b4f4b6742 100644 --- a/Doc/Zsh/builtins.yo +++ b/Doc/Zsh/builtins.yo @@ -1667,7 +1667,7 @@ See also the shell variable tt(STTY) for a means of initialising the tty before running external commands. ) findex(type) -item(tt(type) [ tt(-wfpams) ] var(name) ...)( +item(tt(type) [ tt(-wfpamsS) ] var(name) ...)( Equivalent to tt(whence -v). ) findex(typeset) @@ -2083,7 +2083,7 @@ the user is potentially interested in both, so this problem is intrinsic to process IDs. ) findex(whence) -item(tt(whence) [ tt(-vcwfpams) ] var(name) ...)( +item(tt(whence) [ tt(-vcwfpamsS) ] var(name) ...)( For each name, indicate how it would be interpreted if used as a command name. @@ -2126,6 +2126,11 @@ of these patterns. item(tt(-s))( If a pathname contains symlinks, print the symlink-free pathname as well. ) +item(tt(-S))( +As tt(-s), but if the pathname had to be resolved by following +multiple symlinks, the intermediate steps are printed, too. The +symlink resolved at each step might be anywhere in the path. +) enditem() ) findex(where) diff --git a/Src/builtin.c b/Src/builtin.c index 264169cb4..47d1aa06d 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -119,7 +119,7 @@ static struct builtin builtins[] = BUILTIN("times", BINF_PSPECIAL, bin_times, 0, 0, 0, NULL, NULL), BUILTIN("trap", BINF_PSPECIAL | BINF_HANDLES_OPTS, bin_trap, 0, -1, 0, NULL, NULL), BUILTIN("true", 0, bin_true, 0, -1, 0, NULL, NULL), - BUILTIN("type", 0, bin_whence, 0, -1, 0, "ampfsw", "v"), + BUILTIN("type", 0, bin_whence, 0, -1, 0, "ampfsSw", "v"), BUILTIN("typeset", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%afghi:%klprtuxmz", NULL), BUILTIN("umask", 0, bin_umask, 0, 1, 0, "S", NULL), BUILTIN("unalias", 0, bin_unhash, 1, -1, 0, "ms", "a"), @@ -128,7 +128,7 @@ static struct builtin builtins[] = BUILTIN("unset", BINF_PSPECIAL, bin_unset, 1, -1, 0, "fmv", NULL), BUILTIN("unsetopt", 0, bin_setopt, 0, -1, BIN_UNSETOPT, NULL, NULL), BUILTIN("wait", 0, bin_fg, 0, -1, BIN_WAIT, NULL, NULL), - BUILTIN("whence", 0, bin_whence, 0, -1, 0, "acmpvfsw", NULL), + BUILTIN("whence", 0, bin_whence, 0, -1, 0, "acmpvfsSw", NULL), BUILTIN("where", 0, bin_whence, 0, -1, 0, "pmsw", "ca"), BUILTIN("which", 0, bin_whence, 0, -1, 0, "ampsw", "c"), BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "AFRILP:abcfdilmpue", NULL), @@ -3331,8 +3331,8 @@ bin_whence(char *nam, char **argv, Options ops, int func) if (v && !csh) zputs(*argv, stdout), fputs(" is ", stdout); zputs(buf, stdout); - if (OPT_ISSET(ops,'s')) - print_if_link(buf); + if (OPT_ISSET(ops,'s') || OPT_ISSET(ops, 'S')) + print_if_link(buf, OPT_ISSET(ops, 'S')); fputc('\n', stdout); } informed = 1; @@ -3352,8 +3352,8 @@ bin_whence(char *nam, char **argv, Options ops, int func) if (v && !csh) zputs(*argv, stdout), fputs(" is ", stdout); zputs(cnam, stdout); - if (OPT_ISSET(ops,'s')) - print_if_link(cnam); + if (OPT_ISSET(ops,'s') || OPT_ISSET(ops,'S')) + print_if_link(cnam, OPT_ISSET(ops,'S')); fputc('\n', stdout); } } else { diff --git a/Src/utils.c b/Src/utils.c index 893a8ca02..2b2a815a8 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -719,7 +719,7 @@ slashsplit(char *s) /**/ static int -xsymlinks(char *s) +xsymlinks(char *s, int full) { char **pp, **opp; char xbuf2[PATH_MAX*3], xbuf3[PATH_MAX*2]; @@ -758,14 +758,49 @@ xsymlinks(char *s) } else { ret = 1; metafy(xbuf3, t0, META_NOALLOC); + if (!full) { + /* + * If only one expansion requested, ensure the + * full path is in xbuf. + */ + zulong len = xbuflen; + if (*xbuf3 == '/') + strcpy(xbuf, xbuf3); + else if ((len += strlen(xbuf3) + 1) < sizeof(xbuf)) { + strcpy(xbuf + xbuflen, "/"); + strcpy(xbuf + xbuflen + 1, xbuf3); + } else { + *xbuf = 0; + ret = -1; + break; + } + + while (*++pp) { + zulong newlen = len + strlen(*pp) + 1; + if (newlen < sizeof(xbuf)) { + strcpy(xbuf + len, "/"); + strcpy(xbuf + len + 1, *pp); + len = newlen; + } else { + *xbuf = 01; + ret = -1; + break; + } + } + /* + * No need to update xbuflen, we're finished + * the expansion (for now). + */ + break; + } if (*xbuf3 == '/') { strcpy(xbuf, ""); - if (xsymlinks(xbuf3 + 1) < 0) + if (xsymlinks(xbuf3 + 1, 0) < 0) ret = -1; else xbuflen = strlen(xbuf); } else - if (xsymlinks(xbuf3) < 0) + if (xsymlinks(xbuf3, 0) < 0) ret = -1; else xbuflen = strlen(xbuf); @@ -787,7 +822,7 @@ xsymlink(char *s) if (*s != '/') return NULL; *xbuf = '\0'; - if (xsymlinks(s + 1) < 0) + if (xsymlinks(s + 1, 1) < 0) zwarn("path expansion failed, using root directory"); if (!*xbuf) return ztrdup("/"); @@ -796,12 +831,30 @@ xsymlink(char *s) /**/ void -print_if_link(char *s) +print_if_link(char *s, int all) { if (*s == '/') { *xbuf = '\0'; - if (xsymlinks(s + 1) > 0) - printf(" -> "), zputs(*xbuf ? xbuf : "/", stdout); + if (all) { + char *start = s + 1; + char xbuflink[PATH_MAX]; + for (;;) { + if (xsymlinks(start, 0) > 0) { + printf(" -> "); + zputs(*xbuf ? xbuf : "/", stdout); + if (!*xbuf) + break; + strcpy(xbuflink, xbuf); + start = xbuflink + 1; + *xbuf = '\0'; + } else { + break; + } + } + } else { + if (xsymlinks(s + 1, 1) > 0) + printf(" -> "), zputs(*xbuf ? xbuf : "/", stdout); + } } } -- cgit v1.2.3 From 454bb777cfc9b9c7970ccc1c7574fbf66b83d157 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Fri, 2 Jan 2015 22:25:24 +0000 Subject: users/19671: remove confusion with whence -a. If the argument is a full path don't try to search the path for it. --- ChangeLog | 3 +++ Src/builtin.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'Src/builtin.c') diff --git a/ChangeLog b/ChangeLog index ac957d1df..b78c4c3da 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2015-01-02 Peter Stephenson + * 19671: Src/builtin.c: whence -a should still work if there's a + full path already. + * users/19667: Doc/Zsh/builtins.yo, Src/builtin.c, Src/utils.c: whence -S shows intermediate steps in symlink expansion. diff --git a/Src/builtin.c b/Src/builtin.c index 47d1aa06d..ebc06542e 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -3315,7 +3315,7 @@ bin_whence(char *nam, char **argv, Options ops, int func) /* Option -a is to search the entire path, * * rather than just looking for one match. */ - if (all) { + if (all && **argv != '/') { char **pp, *buf; pushheap(); -- cgit v1.2.3 From f9cc5a6e562842f15ce6e576553f3e0e37e51783 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Sun, 4 Jan 2015 18:12:44 -0800 Subject: 34093: "whence" should always return nonzero when it finds that nothing matches its arguments --- ChangeLog | 10 ++++++++++ Src/builtin.c | 32 +++++++++++++++++--------------- 2 files changed, 27 insertions(+), 15 deletions(-) (limited to 'Src/builtin.c') diff --git a/ChangeLog b/ChangeLog index 75a16bcf7..6fd89cc28 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-01-06 Barton E. Schaefer + + * 34103: Src/subst.c: fix ancient (workers/15872) thinko that + doesn't seem to have mattered, but must in some obscure cases + 2015-01-05 Daniel Shahaf * 34042: Completion/Unix/Command/_git: Respect tags for subcommand @@ -8,6 +13,11 @@ * Timofey Titovets: 34053: Completion/Linux/Command/_modutils: additional compression option for kernel modules. +2015-01-04 Barton E. Schaefer + + * 34093: Src/builtins.c: "whence" should always return nonzero + when it finds that nothing matches its arguments + 2015-01-04 Peter Stephenson * 34092: Src/utils.c: miscount of buffer length in symlink diff --git a/Src/builtin.c b/Src/builtin.c index ebc06542e..4a46cbc1f 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -3173,7 +3173,7 @@ bin_whence(char *nam, char **argv, Options ops, int func) int printflags = 0; int aliasflags; int csh, all, v, wd; - int informed; + int informed = 0; char *cnam, **allmatched = 0; /* Check some option information */ @@ -3207,6 +3207,7 @@ bin_whence(char *nam, char **argv, Options ops, int func) /* With -m option -- treat arguments as a glob patterns */ if (OPT_ISSET(ops,'m')) { + cmdnamtab->filltable(cmdnamtab); if (all) { pushheap(); matchednodes = newlinklist(); @@ -3225,17 +3226,19 @@ bin_whence(char *nam, char **argv, Options ops, int func) /* -p option is for path search only. * * We're not using it, so search for ... */ + informed = /* logical OR of what follows */ + /* aliases ... */ scanmatchtable(aliastab, pprog, 1, 0, DISABLED, - aliastab->printnode, printflags); + aliastab->printnode, printflags) || /* and reserved words ... */ scanmatchtable(reswdtab, pprog, 1, 0, DISABLED, - reswdtab->printnode, printflags); + reswdtab->printnode, printflags) || /* and shell functions... */ scanmatchtable(shfunctab, pprog, 1, 0, DISABLED, - shfunctab->printnode, printflags); + shfunctab->printnode, printflags) || /* and builtins. */ scanmatchtable(builtintab, pprog, 1, 0, DISABLED, @@ -3243,7 +3246,7 @@ bin_whence(char *nam, char **argv, Options ops, int func) } /* Done search for `internal' commands, if the -p option * * was not used. Now search the path. */ - cmdnamtab->filltable(cmdnamtab); + informed += scanmatchtable(cmdnamtab, pprog, 1, 0, 0, (all ? fetchcmdnamnode : cmdnamtab->printnode), printflags); @@ -3255,61 +3258,59 @@ bin_whence(char *nam, char **argv, Options ops, int func) matchednodes = NULL; popheap(); } else - return returnval; + return returnval || !informed; } /* Take arguments literally -- do not glob */ queue_signals(); for (; *argv; argv++) { - informed = 0; - if (!OPT_ISSET(ops,'p') && !allmatched) { char *suf; /* Look for alias */ if ((hn = aliastab->getnode(aliastab, *argv))) { aliastab->printnode(hn, aliasflags); + informed = 1; if (!all) continue; - informed = 1; } /* Look for suffix alias */ if ((suf = strrchr(*argv, '.')) && suf[1] && suf > *argv && suf[-1] != Meta && (hn = sufaliastab->getnode(sufaliastab, suf+1))) { sufaliastab->printnode(hn, printflags); + informed = 1; if (!all) continue; - informed = 1; } /* Look for reserved word */ if ((hn = reswdtab->getnode(reswdtab, *argv))) { reswdtab->printnode(hn, printflags); + informed = 1; if (!all) continue; - informed = 1; } /* Look for shell function */ if ((hn = shfunctab->getnode(shfunctab, *argv))) { shfunctab->printnode(hn, printflags); + informed = 1; if (!all) continue; - informed = 1; } /* Look for builtin command */ if ((hn = builtintab->getnode(builtintab, *argv))) { builtintab->printnode(hn, printflags); + informed = 1; if (!all) continue; - informed = 1; } /* Look for commands that have been added to the * * cmdnamtab with the builtin `hash foo=bar'. */ if ((hn = cmdnamtab->getnode(cmdnamtab, *argv)) && (hn->flags & HASHED)) { cmdnamtab->printnode(hn, printflags); + informed = 1; if (!all) continue; - informed = 1; } } @@ -3356,6 +3357,7 @@ bin_whence(char *nam, char **argv, Options ops, int func) print_if_link(cnam, OPT_ISSET(ops,'S')); fputc('\n', stdout); } + informed = 1; } else { /* Not found at all. */ if (v || csh || wd) @@ -3367,7 +3369,7 @@ bin_whence(char *nam, char **argv, Options ops, int func) freearray(allmatched); unqueue_signals(); - return returnval; + return returnval || !informed; } /**** command & named directory hash table builtins ****/ -- cgit v1.2.3 From a150563fb049b338983156a5be4ff760a0d79c20 Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Mon, 5 Jan 2015 15:53:32 +0100 Subject: 34114: emulate: Handle aborting from mixed -L/-c correctly Somehow Coverity found this (Issue 1255797, Failure to restore non-local value). --- ChangeLog | 5 +++++ Src/builtin.c | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'Src/builtin.c') diff --git a/ChangeLog b/ChangeLog index 6fd89cc28..39599afd5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-01-06 Mikael Magnusson + + * 34114: Src/builtin.c: emulate: Handle aborting from mixed + -L/-c correctly + 2015-01-06 Barton E. Schaefer * 34103: Src/subst.c: fix ancient (workers/15872) thinko that diff --git a/Src/builtin.c b/Src/builtin.c index 4a46cbc1f..afa836a03 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -5173,7 +5173,7 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func)) if (cmd) { if (opt_L) { zwarnnam("emulate", "option -L incompatible with -c"); - goto restore; + goto restore2; } *--argv = cmd; /* on stack, never free()d, see execbuiltin() */ } else @@ -5211,6 +5211,7 @@ bin_emulate(UNUSED(char *nam), char **argv, Options ops, UNUSED(int func)) } ret = eval(argv); sticky = save_sticky; +restore2: emulation = saveemulation; memcpy(opts, saveopts, sizeof(opts)); restorepatterndisables(savepatterns); -- cgit v1.2.3 From 5a9be691858ec25697234cefc5007a8c3fc95803 Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Mon, 5 Jan 2015 15:39:33 +0100 Subject: 34113: whence: use dupstring to not leak memory All other assignments to buf use the heap, and it's never freed. Found by Coverity (Issue 1255786). --- ChangeLog | 2 ++ Src/builtin.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'Src/builtin.c') diff --git a/ChangeLog b/ChangeLog index 4f58df1fa..a000719c5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2015-01-06 Mikael Magnusson + * 34113: Src/builtin.c: whence: use dupstring to not leak memory + * 34119: Src/Zle/complist.c: Fix leak of string in clnicezputs * 34105: Src/subst.c: remove dead code diff --git a/Src/builtin.c b/Src/builtin.c index afa836a03..228eaaada 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -3323,7 +3323,7 @@ bin_whence(char *nam, char **argv, Options ops, int func) for (pp = path; *pp; pp++) { if (**pp) { buf = zhtricat(*pp, "/", *argv); - } else buf = ztrdup(*argv); + } else buf = dupstring(*argv); if (iscom(buf)) { if (wd) { -- cgit v1.2.3 From 1507719d0a5c8ff8694583fbc4c993e937fb9266 Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Mon, 5 Jan 2015 16:08:56 +0100 Subject: 34112: typeset: fix leak of oldval Found by Coverity (Issue 1255803). --- ChangeLog | 2 ++ Src/builtin.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'Src/builtin.c') diff --git a/ChangeLog b/ChangeLog index 321d9fc1d..2afb52cc2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2015-01-06 Mikael Magnusson + * 34112: Src/builtin.c: typeset: fix leak of oldval + * 34106: Src/hist.c: use zhtricat instead of tricat * 34113: Src/builtin.c: whence: use dupstring to not leak memory diff --git a/Src/builtin.c b/Src/builtin.c index 228eaaada..5138c70fd 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -2510,6 +2510,8 @@ bin_typeset(char *name, char **argv, Options ops, int func) asg->name), func, (on | PM_ARRAY) & ~PM_EXPORTED, off, roff, asg->value, NULL, ops, 0))) { + if (oldval) + zsfree(oldval); unqueue_signals(); return 1; } -- cgit v1.2.3 From 93846edb0d5d606e167f929532608eaea273c23f Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Wed, 7 Jan 2015 22:44:21 -0800 Subject: 34154/34155: reorder bin_print() to avoid leaking the output descriptor when incorrect/incompatible options were passed --- ChangeLog | 6 ++++++ Src/builtin.c | 63 ++++++++++++++++++++++++++++++++--------------------------- 2 files changed, 40 insertions(+), 29 deletions(-) (limited to 'Src/builtin.c') diff --git a/ChangeLog b/ChangeLog index b5710fa6a..db143e5bb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2015-01-07 Barton E. Schaefer + + * 34154 (tweaked per 34155): Src/builtin.c: reorder bin_print() to + avoid leaking the output descriptor when incorrect/incompatible + options were passed + 2015-01-07 Jun-ichi Takimoto * 34144: Src/Zle/zle_tricky.c, Src/Zle/complist.c: allocate diff --git a/Src/builtin.c b/Src/builtin.c index 5138c70fd..d9ca95a53 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -3724,7 +3724,7 @@ int bin_print(char *name, char **args, Options ops, int func) { int flen, width, prec, type, argc, n, narg, curlen = 0; - int nnl = 0, fmttrunc = 0, ret = 0, maxarg = 0; + int nnl = 0, fmttrunc = 0, ret = 0, maxarg = 0, nc = 0; int flags[5], *len; char *start, *endptr, *c, *d, *flag, *buf, spec[13], *fmt = NULL; char **first, **argp, *curarg, *flagch = "0+- #", save = '\0', nullstr = '\0'; @@ -3837,8 +3837,38 @@ bin_print(char *name, char **args, Options ops, int func) } } + /* -o and -O -- sort the arguments */ + if (OPT_ISSET(ops,'o') || OPT_ISSET(ops,'O')) { + int flags; + + if (fmt && !*args) + return 0; + flags = OPT_ISSET(ops,'i') ? SORTIT_IGNORING_CASE : 0; + if (OPT_ISSET(ops,'O')) + flags |= SORTIT_BACKWARDS; + strmetasort(args, flags, len); + } + + /* -C -- number of columns */ + if (!fmt && OPT_ISSET(ops,'C')) { + char *eptr, *argptr = OPT_ARG(ops,'C'); + nc = (int)zstrtol(argptr, &eptr, 10); + if (*eptr) { + zwarnnam(name, "number expcted after -%c: %s", 'C', argptr); + return 1; + } + if (nc <= 0) { + zwarnnam(name, "invalid number of columns: %s", argptr); + return 1; + } + } + /* -u and -p -- output to other than standard output */ - if (OPT_HASARG(ops,'u') || OPT_ISSET(ops,'p')) { + if ((OPT_HASARG(ops,'u') || OPT_ISSET(ops,'p')) && + /* rule out conflicting options -- historical precedence */ + ((!fmt && (OPT_ISSET(ops,'c') || OPT_ISSET(ops,'C'))) || + !(OPT_ISSET(ops, 'z') || + OPT_ISSET(ops, 's') || OPT_ISSET(ops, 'S')))) { int fdarg, fd; if (OPT_ISSET(ops, 'p')) { @@ -3877,24 +3907,9 @@ bin_print(char *name, char **args, Options ops, int func) } } - /* -o and -O -- sort the arguments */ - if (OPT_ISSET(ops,'o') || OPT_ISSET(ops,'O')) { - int flags; - - if (fmt && !*args) { - if (fout != stdout) - fclose(fout); - return 0; - } - flags = OPT_ISSET(ops,'i') ? SORTIT_IGNORING_CASE : 0; - if (OPT_ISSET(ops,'O')) - flags |= SORTIT_BACKWARDS; - strmetasort(args, flags, len); - } - /* -c -- output in columns */ if (!fmt && (OPT_ISSET(ops,'c') || OPT_ISSET(ops,'C'))) { - int l, nc, nr, sc, n, t, i; + int l, nr, sc, n, t, i; #ifdef MULTIBYTE_SUPPORT int *widths; @@ -3965,19 +3980,9 @@ bin_print(char *name, char **args, Options ops, int func) #endif if (OPT_ISSET(ops,'C')) { - char *eptr, *argptr = OPT_ARG(ops,'C'); - nc = (int)zstrtol(argptr, &eptr, 10); - if (*eptr) { - zwarnnam(name, "number expcted after -%c: %s", 'C', argptr); - return 1; - } - if (nc <= 0) { - zwarnnam(name, "invalid number of columns: %s", argptr); - return 1; - } /* * n: number of elements - * nc: number of columns + * nc: number of columns (above) * nr: number of rows */ n = arrlen(args); -- cgit v1.2.3 From bc55ddf364535347a24a28222874038b4b64913d Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Fri, 9 Jan 2015 12:33:57 +0100 Subject: Fix a typo in bin_print error message --- Src/builtin.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Src/builtin.c') diff --git a/Src/builtin.c b/Src/builtin.c index d9ca95a53..d2108264f 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -3784,7 +3784,7 @@ bin_print(char *name, char **args, Options ops, int func) /* compute lengths, and interpret according to -P, -D, -e, etc. */ argc = arrlen(args); len = (int *) hcalloc(argc * sizeof(int)); - for(n = 0; n < argc; n++) { + for (n = 0; n < argc; n++) { /* first \ sequences */ if (fmt || (!OPT_ISSET(ops,'e') && @@ -3854,7 +3854,7 @@ bin_print(char *name, char **args, Options ops, int func) char *eptr, *argptr = OPT_ARG(ops,'C'); nc = (int)zstrtol(argptr, &eptr, 10); if (*eptr) { - zwarnnam(name, "number expcted after -%c: %s", 'C', argptr); + zwarnnam(name, "number expected after -%c: %s", 'C', argptr); return 1; } if (nc <= 0) { @@ -3881,7 +3881,7 @@ bin_print(char *name, char **args, Options ops, int func) char *argptr = OPT_ARG(ops,'u'), *eptr; /* Handle undocumented feature that -up worked */ if (!strcmp(argptr, "p")) { - fdarg= coprocout; + fdarg = coprocout; if (fdarg < 0) { zwarnnam(name, "-p: no coprocess"); return 1; -- cgit v1.2.3 From cfd91eac0732da8ece012ca4ab051d928a85c9dd Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 8 Jan 2015 21:39:26 +0000 Subject: Rearrange context saving. Variables are now associated with the module that declares them, being initialised and saved/restored there. However, as many variables are used for communication between modules, many of them are set in multiple places, so the assignment is ambiguous. --- ChangeLog | 9 ++ Src/Zle/compcore.c | 4 +- Src/Zle/compctl.c | 8 +- Src/Zle/textobjects.c | 4 +- Src/Zle/zle_tricky.c | 24 ++-- Src/builtin.c | 8 +- Src/context.c | 116 ++++++++++++++++++ Src/exec.c | 8 +- Src/hist.c | 88 +++++++++++++- Src/init.c | 4 +- Src/lex.c | 321 ++++++++++---------------------------------------- Src/parse.c | 83 ++++++++++++- Src/signals.c | 4 +- Src/zsh.h | 65 ++++++++++ Src/zsh.mdd | 3 +- 15 files changed, 450 insertions(+), 299 deletions(-) create mode 100644 Src/context.c (limited to 'Src/builtin.c') diff --git a/ChangeLog b/ChangeLog index c4ea61b41..a78425bda 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2015-01-09 Peter Stephenson + + * 34189: Src/Zle/compcore.c, Src/Zle/compctl.c, + Src/Zle/textobjects.c, Src/Zle/zle_tricky.c, Src/builtin.c, + Src/context.c, Src/exec.c, Src/hist.c, Src/init.c, Src/lex.c, + Src/parse.c, Src/signals.c, Src/zsh.h, Src/zsh.mdd: + vain attempt to make context save and restore neater and + control the status variables thereby managed. + 2015-01-09 Peter Stephenson * 34182: Doc/Zsh/mod_files.yo: to add zf_* builtins you can diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index f5056058a..000f9da2a 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -1524,7 +1524,7 @@ set_comp_sep(void) ol = zlemetaline; addedx = 1; noerrs = 1; - lexsave(); + zcontext_save(); lexflags = LEXFLAGS_ZLE; /* * tl is the length of the temporary string including @@ -1673,7 +1673,7 @@ set_comp_sep(void) inpop(); errflag &= ~ERRFLAG_ERROR; noerrs = ne; - lexrestore(); + zcontext_restore(); wb = owb; we = owe; zlemetaline = ol; diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index 2a80e6c84..43dd4e2a9 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -2795,7 +2795,7 @@ sep_comp_string(char *ss, char *s, int noffs) * get the words we have to expand. */ addedx = 1; noerrs = 1; - lexsave(); + zcontext_save(); lexflags = LEXFLAGS_ZLE; tmp = (char *) zhalloc(tl = sl + 3 + strlen(s)); strcpy(tmp, ss); @@ -2849,7 +2849,7 @@ sep_comp_string(char *ss, char *s, int noffs) inpop(); errflag &= ~ERRFLAG_ERROR; noerrs = ne; - lexrestore(); + zcontext_restore(); wb = owb; we = owe; zlemetacs = ocs; @@ -3707,7 +3707,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) /* Put the string in the lexer buffer and call the lexer to * * get the words we have to expand. */ - lexsave(); + zcontext_save(); lexflags = LEXFLAGS_ZLE; tmpbuf = (char *)zhalloc(strlen(cc->str) + 5); sprintf(tmpbuf, "foo %s", cc->str); /* KLUDGE! */ @@ -3726,7 +3726,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) strinend(); inpop(); errflag &= ~ERRFLAG_ERROR; - lexrestore(); + zcontext_restore(); /* Fine, now do full expansion. */ prefork(foo, 0); if (!errflag) { diff --git a/Src/Zle/textobjects.c b/Src/Zle/textobjects.c index 37d2c0ad9..9b3277a97 100644 --- a/Src/Zle/textobjects.c +++ b/Src/Zle/textobjects.c @@ -241,7 +241,7 @@ selectargument(UNUSED(char **args)) addedx = 0; noerrs = 1; - lexsave(); + zcontext_save(); lexflags = LEXFLAGS_ACTIVE; linein = zlegetline(&ll, &cs); zlemetall = ll; @@ -277,7 +277,7 @@ selectargument(UNUSED(char **args)) inpop(); errflag &= ~ERRFLAG_ERROR; noerrs = ne; - lexrestore(); + zcontext_restore(); zlemetacs = ocs; wb = owb; we = owe; diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index 950c22f38..f18ad170e 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -698,7 +698,7 @@ docomplete(int lst) freeheap(); /* Save the lexer state, in case the completion code uses the lexer * * somewhere (e.g. when processing a compctl -s flag). */ - lexsave(); + zcontext_save(); if (inwhat == IN_ENV) lincmd = 0; if (s) { @@ -868,7 +868,7 @@ docomplete(int lst) } else ret = 1; /* Reset the lexer state, pop the heap. */ - lexrestore(); + zcontext_restore(); popheap(); dat[0] = lst; @@ -1164,7 +1164,7 @@ get_comp_string(void) varname = NULL; insubscr = 0; clwpos = -1; - lexsave(); + zcontext_save(); lexflags = LEXFLAGS_ZLE; inpush(dupstrspace(linptr), 0, NULL); strinbeg(0); @@ -1422,7 +1422,7 @@ get_comp_string(void) zlemetall -= parend; zlemetaline[zlemetall + addedx] = '\0'; } - lexrestore(); + zcontext_restore(); tt = NULL; goto start; } @@ -1496,12 +1496,12 @@ get_comp_string(void) if (tmp) { tmp = NULL; linptr = zlemetaline; - lexrestore(); + zcontext_restore(); addedx = 0; goto start; } noaliases = ona; - lexrestore(); + zcontext_restore(); return NULL; } @@ -2151,7 +2151,7 @@ get_comp_string(void) offs = boffs; } } - lexrestore(); + zcontext_restore(); return (char *)s; } @@ -2791,7 +2791,7 @@ doexpandhist(void) expanding = 1; excs = zlemetacs; zlemetall = zlemetacs = 0; - lexsave(); + zcontext_save(); /* We push ol as it will remain unchanged */ inpush(ol, 0, NULL); strinbeg(1); @@ -2803,7 +2803,7 @@ doexpandhist(void) } while (tok != ENDINPUT && tok != LEXERR); while (!lexstop) hgetc(); - /* We have to save errflags because it's reset in lexrestore. Since * + /* We have to save errflags because it's reset in zcontext_restore. Since * * noerrs was set to 1 errflag is true if there was a habort() which * * means that the expanded string is unusable. */ err = errflag; @@ -2811,7 +2811,7 @@ doexpandhist(void) noaliases = ona; strinend(); inpop(); - lexrestore(); + zcontext_restore(); expanding = 0; if (!err) { @@ -2910,7 +2910,7 @@ getcurcmd(void) int curlincmd; char *s = NULL; - lexsave(); + zcontext_save(); lexflags = LEXFLAGS_ZLE; metafy_line(); inpush(dupstrspace(zlemetaline), 0, NULL); @@ -2934,7 +2934,7 @@ getcurcmd(void) inpop(); errflag &= ~ERRFLAG_ERROR; unmetafy_line(); - lexrestore(); + zcontext_restore(); return s; } diff --git a/Src/builtin.c b/Src/builtin.c index d2108264f..8abe728db 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -6102,7 +6102,7 @@ bin_test(char *name, char **argv, UNUSED(Options ops), int func) } } - lexsave(); + zcontext_save(); testargs = argv; tok = NULLTOK; condlex = testlex; @@ -6112,16 +6112,16 @@ bin_test(char *name, char **argv, UNUSED(Options ops), int func) if (errflag) { errflag &= ~ERRFLAG_ERROR; - lexrestore(); + zcontext_restore(); return 1; } if (!prog || tok == LEXERR) { zwarnnam(name, tokstr ? "parse error" : "argument expected"); - lexrestore(); + zcontext_restore(); return 1; } - lexrestore(); + zcontext_restore(); if (*curtestarg) { zwarnnam(name, "too many arguments"); diff --git a/Src/context.c b/Src/context.c new file mode 100644 index 000000000..bd8d191bf --- /dev/null +++ b/Src/context.c @@ -0,0 +1,116 @@ +/* + * context.c - context save and restore + * + * This file is part of zsh, the Z shell. + * + * Copyright (c) 1992-1997 Paul Falstad + * All rights reserved. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and to distribute modified versions of this software for any + * purpose, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * In no event shall Paul Falstad or the Zsh Development Group be liable + * to any party for direct, indirect, special, incidental, or consequential + * damages arising out of the use of this software and its documentation, + * even if Paul Falstad and the Zsh Development Group have been advised of + * the possibility of such damage. + * + * Paul Falstad and the Zsh Development Group specifically disclaim any + * warranties, including, but not limited to, the implied warranties of + * merchantability and fitness for a particular purpose. The software + * provided hereunder is on an "as is" basis, and Paul Falstad and the + * Zsh Development Group have no obligation to provide maintenance, + * support, updates, enhancements, or modifications. + * + */ +/* + * This short file provides a home for the stack of saved contexts. + * The actions for saving and restoring are encapsulated within + * individual modules. + */ + +#include "zsh.mdh" +#include "context.pro" + +struct context_stack { + struct context_stack *next; + + struct hist_stack hist_stack; + struct lex_stack lex_stack; + struct parse_stack parse_stack; +}; + +static struct context_stack *cstack; + +/* save some or all of current context */ + +/**/ +mod_export void +zcontext_save_partial(int parts) +{ + struct context_stack *cs; + + cs = (struct context_stack *)malloc(sizeof(struct context_stack)); + + if (parts & ZCONTEXT_HIST) { + hist_context_save(&cs->hist_stack, !cstack); + } + if (parts & ZCONTEXT_LEX) { + lex_context_save(&cs->lex_stack, !cstack); + } + if (parts & ZCONTEXT_PARSE) { + parse_context_save(&cs->parse_stack, !cstack); + } + + cs->next = cstack; + cstack = cs; +} + +/* save context in full */ + +/**/ +mod_export void +zcontext_save(void) +{ + zcontext_save_partial(ZCONTEXT_HIST|ZCONTEXT_LEX|ZCONTEXT_PARSE); +} + +/* restore context or part thereof */ + +/**/ +mod_export void +zcontext_restore_partial(int parts) +{ + struct context_stack *cs = cstack; + + DPUTS(!cstack, "BUG: zcontext_restore() without zcontext_save()"); + + queue_signals(); + cstack = cstack->next; + + if (parts & ZCONTEXT_HIST) { + hist_context_restore(&cs->hist_stack, !cstack); + } + if (parts & ZCONTEXT_LEX) { + lex_context_restore(&cs->lex_stack, !cstack); + } + if (parts & ZCONTEXT_PARSE) { + parse_context_restore(&cs->parse_stack, !cstack); + } + + free(cs); + + unqueue_signals(); +} + +/* restore full context */ + +/**/ +mod_export void +zcontext_restore(void) +{ + zcontext_restore_partial(ZCONTEXT_HIST|ZCONTEXT_LEX|ZCONTEXT_PARSE); +} diff --git a/Src/exec.c b/Src/exec.c index ab9291024..7b6495113 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -217,7 +217,7 @@ parse_string(char *s, int reset_lineno) Eprog p; zlong oldlineno; - lexsave(); + zcontext_save(); inpush(s, INP_LINENO, NULL); strinbeg(0); oldlineno = lineno; @@ -229,7 +229,7 @@ parse_string(char *s, int reset_lineno) lastval = 1; strinend(); inpop(); - lexrestore(); + zcontext_restore(); return p; } @@ -3349,9 +3349,9 @@ execcmd(Estate state, int input, int output, int how, int last1) * The copy uses the wordcode parsing area, so save and * restore state. */ - lexsave(); + zcontext_save(); redir_prog = eccopyredirs(&s); - lexrestore(); + zcontext_restore(); } else redir_prog = NULL; diff --git a/Src/hist.c b/Src/hist.c index e65d78bfd..447f00e84 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -222,6 +222,85 @@ static int histsave_stack_pos = 0; static zlong histfile_linect; +/* save history context */ + +/**/ +void +hist_context_save(struct hist_stack *hs, int toplevel) +{ + if (toplevel) { + /* top level, make this version visible to ZLE */ + zle_chline = chline; + /* ensure line stored is NULL-terminated */ + if (hptr) + *hptr = '\0'; + } + hs->histactive = histactive; + hs->histdone = histdone; + hs->stophist = stophist; + hs->hline = chline; + hs->hptr = hptr; + hs->chwords = chwords; + hs->chwordlen = chwordlen; + hs->chwordpos = chwordpos; + hs->hwgetword = hwgetword; + hs->hgetc = hgetc; + hs->hungetc = hungetc; + hs->hwaddc = hwaddc; + hs->hwbegin = hwbegin; + hs->hwend = hwend; + hs->addtoline = addtoline; + hs->hlinesz = hlinesz; + /* + * We save and restore the command stack with history + * as it's visible to the user interactively, so if + * we're preserving history state we'll continue to + * show the current set of commands from input. + */ + hs->cstack = cmdstack; + hs->csp = cmdsp; + + stophist = 0; + chline = NULL; + hptr = NULL; + histactive = 0; + cmdstack = (unsigned char *)zalloc(CMDSTACKSZ); + cmdsp = 0; +} + +/**/ +void +hist_context_restore(const struct hist_stack *hs, int toplevel) +{ + if (toplevel) { + /* Back to top level: don't need special ZLE value */ + DPUTS(hs->hline != zle_chline, "BUG: Ouch, wrong chline for ZLE"); + zle_chline = NULL; + } + histactive = hs->histactive; + histdone = hs->histdone; + stophist = hs->stophist; + chline = hs->hline; + hptr = hs->hptr; + chwords = hs->chwords; + chwordlen = hs->chwordlen; + chwordpos = hs->chwordpos; + hwgetword = hs->hwgetword; + hgetc = hs->hgetc; + hungetc = hs->hungetc; + hwaddc = hs->hwaddc; + hwbegin = hs->hwbegin; + hwend = hs->hwend; + addtoline = hs->addtoline; + hlinesz = hs->hlinesz; + if (cmdstack) + zfree(cmdstack, CMDSTACKSZ); + cmdstack = hs->cstack; + cmdsp = hs->csp; +} + +/* restore history context */ + /* add a character to the current history word */ static void @@ -815,6 +894,11 @@ strinbeg(int dohist) strin++; hbegin(dohist); lexinit(); + /* + * Also initialise some variables owned by the parser but + * used for communication between the parser and lexer. + */ + init_parse_status(); } /* done reading a string */ @@ -2992,7 +3076,7 @@ bufferwords(LinkList list, char *buf, int *index, int flags) opts[RCQUOTES] = 0; addedx = 0; noerrs = 1; - lexsave(); + zcontext_save(); lexflags = flags | LEXFLAGS_ACTIVE; /* * Are we handling comments? @@ -3189,7 +3273,7 @@ bufferwords(LinkList list, char *buf, int *index, int flags) errflag &= ~ERRFLAG_ERROR; nocomments = onc; noerrs = ne; - lexrestore(); + zcontext_restore(); zlemetacs = ocs; zlemetall = oll; wb = owb; diff --git a/Src/init.c b/Src/init.c index 080fc8561..e7d86feac 100644 --- a/Src/init.c +++ b/Src/init.c @@ -107,7 +107,7 @@ loop(int toplevel, int justonce) pushheap(); if (!toplevel) - lexsave(); + zcontext_save(); for (;;) { freeheap(); if (stophist == 3) /* re-entry via preprompt() */ @@ -227,7 +227,7 @@ loop(int toplevel, int justonce) } err = errflag; if (!toplevel) - lexrestore(); + zcontext_restore(); popheap(); if (err) diff --git a/Src/lex.c b/Src/lex.c index d440f3d70..69441b28d 100644 --- a/Src/lex.c +++ b/Src/lex.c @@ -203,263 +203,64 @@ static int dbparens; static int len = 0, bsiz = 256; static char *bptr; -struct lexstack { - struct lexstack *next; - - int incmdpos; - int incond; - int incasepat; - int dbparens; - int isfirstln; - int isfirstch; - int histactive; - int histdone; - int lexflags; - int stophist; - int hlinesz; - char *hline; - char *hptr; - enum lextok tok; - int isnewlin; - char *tokstr; - char *zshlextext; - char *bptr; - int bsiz; - int len; - int lex_add_raw; - char *tokstr_raw; - char *bptr_raw; - int bsiz_raw; - int len_raw; - short *chwords; - int chwordlen; - int chwordpos; - int hwgetword; - int lexstop; - struct heredocs *hdocs; - int (*hgetc) _((void)); - void (*hungetc) _((int)); - void (*hwaddc) _((int)); - void (*hwbegin) _((int)); - void (*hwend) _((void)); - void (*addtoline) _((int)); - - int eclen, ecused, ecnpats; - Wordcode ecbuf; - Eccstr ecstrs; - int ecsoffs, ecssub, ecnfunc; - - unsigned char *cstack; - int csp; - zlong toklineno; -}; - -static struct lexstack *lstack = NULL; - -/* save the context or parts thereof */ - -/* is this a hack or what? */ +/* save lexical context */ /**/ -mod_export void -lexsave_partial(int parts) -{ - struct lexstack *ls; - - ls = (struct lexstack *)malloc(sizeof(struct lexstack)); - - if (parts & ZCONTEXT_LEX) { - ls->incmdpos = incmdpos; - ls->incond = incond; - ls->incasepat = incasepat; - ls->dbparens = dbparens; - ls->isfirstln = isfirstln; - ls->isfirstch = isfirstch; - ls->lexflags = lexflags; - - ls->tok = tok; - ls->isnewlin = isnewlin; - ls->tokstr = tokstr; - ls->zshlextext = zshlextext; - ls->bptr = bptr; - ls->bsiz = bsiz; - ls->len = len; - ls->lex_add_raw = lex_add_raw; - ls->tokstr_raw = tokstr_raw; - ls->bptr_raw = bptr_raw; - ls->bsiz_raw = bsiz_raw; - ls->len_raw = len_raw; - ls->lexstop = lexstop; - ls->toklineno = toklineno; - - tokstr = zshlextext = bptr = NULL; - bsiz = 256; - tokstr_raw = bptr_raw = NULL; - bsiz_raw = len_raw = lex_add_raw = 0; - - inredir = 0; - } - if (parts & ZCONTEXT_HIST) { - if (!lstack) { - /* top level, make this version visible to ZLE */ - zle_chline = chline; - /* ensure line stored is NULL-terminated */ - if (hptr) - *hptr = '\0'; - } - ls->histactive = histactive; - ls->histdone = histdone; - ls->stophist = stophist; - ls->hline = chline; - ls->hptr = hptr; - ls->chwords = chwords; - ls->chwordlen = chwordlen; - ls->chwordpos = chwordpos; - ls->hwgetword = hwgetword; - ls->hgetc = hgetc; - ls->hungetc = hungetc; - ls->hwaddc = hwaddc; - ls->hwbegin = hwbegin; - ls->hwend = hwend; - ls->addtoline = addtoline; - ls->hlinesz = hlinesz; - /* - * We save and restore the command stack with history - * as it's visible to the user interactively, so if - * we're preserving history state we'll continue to - * show the current set of commands from input. - */ - ls->cstack = cmdstack; - ls->csp = cmdsp; - - stophist = 0; - chline = NULL; - hptr = NULL; - histactive = 0; - cmdstack = (unsigned char *)zalloc(CMDSTACKSZ); - cmdsp = 0; - } - if (parts & ZCONTEXT_PARSE) { - ls->hdocs = hdocs; - ls->eclen = eclen; - ls->ecused = ecused; - ls->ecnpats = ecnpats; - ls->ecbuf = ecbuf; - ls->ecstrs = ecstrs; - ls->ecsoffs = ecsoffs; - ls->ecssub = ecssub; - ls->ecnfunc = ecnfunc; - ecbuf = NULL; - hdocs = NULL; - } - - ls->next = lstack; - lstack = ls; -} - -/* save context in full */ - -/**/ -mod_export void -lexsave(void) -{ - lexsave_partial(ZCONTEXT_HIST|ZCONTEXT_LEX|ZCONTEXT_PARSE); -} - -/* restore context or part therefore */ - -/**/ -mod_export void -lexrestore_partial(int parts) +void +lex_context_save(struct lex_stack *ls, int toplevel) { - struct lexstack *ln = lstack; - - DPUTS(!lstack, "BUG: lexrestore() without lexsave()"); - - queue_signals(); - lstack = lstack->next; - - if (parts & ZCONTEXT_LEX) { - incmdpos = ln->incmdpos; - incond = ln->incond; - incasepat = ln->incasepat; - dbparens = ln->dbparens; - isfirstln = ln->isfirstln; - isfirstch = ln->isfirstch; - lexflags = ln->lexflags; - tok = ln->tok; - isnewlin = ln->isnewlin; - tokstr = ln->tokstr; - zshlextext = ln->zshlextext; - bptr = ln->bptr; - bsiz = ln->bsiz; - len = ln->len; - lex_add_raw = ln->lex_add_raw; - tokstr_raw = ln->tokstr_raw; - bptr_raw = ln->bptr_raw; - bsiz_raw = ln->bsiz_raw; - len_raw = ln->len_raw; - lexstop = ln->lexstop; - toklineno = ln->toklineno; - } - - if (parts & ZCONTEXT_HIST) { - if (!lstack) { - /* Back to top level: don't need special ZLE value */ - DPUTS(ln->hline != zle_chline, "BUG: Ouch, wrong chline for ZLE"); - zle_chline = NULL; - } - histactive = ln->histactive; - histdone = ln->histdone; - stophist = ln->stophist; - chline = ln->hline; - hptr = ln->hptr; - chwords = ln->chwords; - chwordlen = ln->chwordlen; - chwordpos = ln->chwordpos; - hwgetword = ln->hwgetword; - hgetc = ln->hgetc; - hungetc = ln->hungetc; - hwaddc = ln->hwaddc; - hwbegin = ln->hwbegin; - hwend = ln->hwend; - addtoline = ln->addtoline; - hlinesz = ln->hlinesz; - if (cmdstack) - zfree(cmdstack, CMDSTACKSZ); - cmdstack = ln->cstack; - cmdsp = ln->csp; - } - - if (parts & ZCONTEXT_PARSE) { - if (ecbuf) - zfree(ecbuf, eclen); - - hdocs = ln->hdocs; - eclen = ln->eclen; - ecused = ln->ecused; - ecnpats = ln->ecnpats; - ecbuf = ln->ecbuf; - ecstrs = ln->ecstrs; - ecsoffs = ln->ecsoffs; - ecssub = ln->ecssub; - ecnfunc = ln->ecnfunc; - - errflag &= ~ERRFLAG_ERROR; - } - - free(ln); - - unqueue_signals(); + (void)toplevel; + + ls->dbparens = dbparens; + ls->isfirstln = isfirstln; + ls->isfirstch = isfirstch; + ls->lexflags = lexflags; + + ls->tok = tok; + ls->tokstr = tokstr; + ls->zshlextext = zshlextext; + ls->bptr = bptr; + ls->bsiz = bsiz; + ls->len = len; + ls->lex_add_raw = lex_add_raw; + ls->tokstr_raw = tokstr_raw; + ls->bptr_raw = bptr_raw; + ls->bsiz_raw = bsiz_raw; + ls->len_raw = len_raw; + ls->lexstop = lexstop; + ls->toklineno = toklineno; + + tokstr = zshlextext = bptr = NULL; + bsiz = 256; + tokstr_raw = bptr_raw = NULL; + bsiz_raw = len_raw = lex_add_raw = 0; } -/* complete restore context */ +/* restore lexical context */ /**/ mod_export void -lexrestore(void) +lex_context_restore(const struct lex_stack *ls, int toplevel) { - lexrestore_partial(ZCONTEXT_HIST|ZCONTEXT_LEX|ZCONTEXT_PARSE); + (void)toplevel; + + dbparens = ls->dbparens; + isfirstln = ls->isfirstln; + isfirstch = ls->isfirstch; + lexflags = ls->lexflags; + tok = ls->tok; + tokstr = ls->tokstr; + zshlextext = ls->zshlextext; + bptr = ls->bptr; + bsiz = ls->bsiz; + len = ls->len; + lex_add_raw = ls->lex_add_raw; + tokstr_raw = ls->tokstr_raw; + bptr_raw = ls->bptr_raw; + bsiz_raw = ls->bsiz_raw; + len_raw = ls->len_raw; + lexstop = ls->lexstop; + toklineno = ls->toklineno; } /**/ @@ -634,9 +435,7 @@ initlextabs(void) void lexinit(void) { - incond = incasepat = nocorrect = - infor = dbparens = lexstop = 0; - incmdpos = 1; + nocorrect = dbparens = lexstop = 0; tok = ENDINPUT; } @@ -1725,7 +1524,7 @@ parsestrnoerr(char *s) { int l = strlen(s), err; - lexsave(); + zcontext_save(); untokenize(s); inpush(dupstring(s), 0, NULL); strinbeg(0); @@ -1737,7 +1536,7 @@ parsestrnoerr(char *s) strinend(); inpop(); DPUTS(cmdsp, "BUG: parsestr: cmdstack not empty."); - lexrestore(); + zcontext_restore(); return err; } @@ -1756,7 +1555,7 @@ parse_subscript(char *s, int sub, int endchar) if (!*s || *s == endchar) return 0; - lexsave(); + zcontext_save(); untokenize(t = dupstring(s)); inpush(t, 0, NULL); strinbeg(0); @@ -1776,7 +1575,7 @@ parse_subscript(char *s, int sub, int endchar) strinend(); inpop(); DPUTS(cmdsp, "BUG: parse_subscript: cmdstack not empty."); - lexrestore(); + zcontext_restore(); return s; } @@ -1794,7 +1593,7 @@ parse_subst_string(char *s) if (!*s || !strcmp(s, nulstring)) return 0; - lexsave(); + zcontext_save(); untokenize(s); inpush(dupstring(s), 0, NULL); strinbeg(0); @@ -1807,7 +1606,7 @@ parse_subst_string(char *s) strinend(); inpop(); DPUTS(cmdsp, "BUG: parse_subst_string: cmdstack not empty."); - lexrestore(); + zcontext_restore(); /* Keep any interrupt error status */ errflag = err | (errflag & ERRFLAG_INT); if (ctok == LEXERR) { @@ -1817,7 +1616,7 @@ parse_subst_string(char *s) #ifdef DEBUG /* * Historical note: we used to check here for olen (the value of len - * before lexrestore()) == l, but that's not necessarily the case if + * before zcontext_restore()) == l, but that's not necessarily the case if * we stripped an RCQUOTE. */ if (ctok != STRING || (errflag && !noerrs)) { @@ -2047,7 +1846,7 @@ skipcomm(void) new_len = len; new_bsiz = bsiz; - lexsave_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE); + zcontext_save_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE); } else { /* * Set up for nested command subsitution, however @@ -2063,7 +1862,7 @@ skipcomm(void) new_len = len_raw; new_bsiz = bsiz_raw; - lexsave_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE); + zcontext_save_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE); } tokstr_raw = new_tokstr; bsiz_raw = new_bsiz; @@ -2090,7 +1889,7 @@ skipcomm(void) */ new_lexstop = lexstop; - lexrestore_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE); + zcontext_restore_partial(ZCONTEXT_LEX|ZCONTEXT_PARSE); if (lex_add_raw) { /* diff --git a/Src/parse.c b/Src/parse.c index fa37ca3d9..0b54a904d 100644 --- a/Src/parse.c +++ b/Src/parse.c @@ -31,7 +31,7 @@ #include "parse.pro" /* != 0 if we are about to read a command word */ - + /**/ mod_export int incmdpos; @@ -242,6 +242,67 @@ int ecsoffs, ecssub, ecnfunc; #define EC_DOUBLE_THRESHOLD 32768 #define EC_INCREMENT 1024 +/* save parse context */ + +/**/ +void +parse_context_save(struct parse_stack *ps, int toplevel) +{ + (void)toplevel; + + ps->incmdpos = incmdpos; + ps->aliasspaceflag = aliasspaceflag; + ps->incond = incond; + ps->inredir = inredir; + ps->incasepat = incasepat; + ps->isnewlin = isnewlin; + ps->infor = infor; + + ps->hdocs = hdocs; + ps->eclen = eclen; + ps->ecused = ecused; + ps->ecnpats = ecnpats; + ps->ecbuf = ecbuf; + ps->ecstrs = ecstrs; + ps->ecsoffs = ecsoffs; + ps->ecssub = ecssub; + ps->ecnfunc = ecnfunc; + ecbuf = NULL; + hdocs = NULL; +} + +/* restore parse context */ + +/**/ +void +parse_context_restore(const struct parse_stack *ps, int toplevel) +{ + (void)toplevel; + + if (ecbuf) + zfree(ecbuf, eclen); + + incmdpos = ps->incmdpos; + aliasspaceflag = ps->aliasspaceflag; + incond = ps->incond; + inredir = ps->inredir; + incasepat = ps->incasepat; + incasepat = ps->incasepat; + isnewlin = ps->isnewlin; + infor = ps->infor; + + hdocs = ps->hdocs; + eclen = ps->eclen; + ecused = ps->ecused; + ecnpats = ps->ecnpats; + ecbuf = ps->ecbuf; + ecstrs = ps->ecstrs; + ecsoffs = ps->ecsoffs; + ecssub = ps->ecssub; + ecnfunc = ps->ecnfunc; + + errflag &= ~ERRFLAG_ERROR; +} /* Adjust pointers in here-doc structs. */ @@ -359,6 +420,21 @@ ecstrcode(char *s) } while (0) +/**/ +mod_export void +init_parse_status(void) +{ + /* + * These variables are currently declared by the parser, so we + * initialise them here. Possibly they are more naturally declared + * by the lexical anaylser; however, as they are used for signalling + * between the two it's a bit ambiguous. We clear them when + * using the lexical analyser for strings as well as here. + */ + incasepat = incond = inredir = infor = 0; + incmdpos = 1; +} + /* Initialise wordcode buffer. */ /**/ @@ -373,6 +449,8 @@ init_parse(void) ecsoffs = ecnpats = 0; ecssub = 0; ecnfunc = 0; + + init_parse_status(); } /* Build eprog. */ @@ -539,9 +617,8 @@ parse_list(void) int c = 0; tok = ENDINPUT; - incmdpos = 1; - zshlex(); init_parse(); + zshlex(); par_list(&c); if (tok != ENDINPUT) { clear_hdocs(); diff --git a/Src/signals.c b/Src/signals.c index 899f1217b..3950ad1a2 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -1210,7 +1210,7 @@ dotrapargs(int sig, int *sigtr, void *sigfn) intrap++; *sigtr |= ZSIG_IGNORED; - lexsave(); + zcontext_save(); /* execsave will save the old trap_return and trap_state */ execsave(); breaks = retflag = 0; @@ -1265,7 +1265,7 @@ dotrapargs(int sig, int *sigtr, void *sigfn) new_trap_return = trap_return; execrestore(); - lexrestore(); + zcontext_restore(); if (new_trap_state == TRAP_STATE_FORCE_RETURN && /* zero return from function isn't special */ diff --git a/Src/zsh.h b/Src/zsh.h index 475b7824f..8fb4f977a 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -2691,6 +2691,71 @@ struct sortelt { typedef struct sortelt *SortElt; +/*********************************************************/ +/* Structures to save and restore for individual modules */ +/*********************************************************/ + +/* History */ +struct hist_stack { + int histactive; + int histdone; + int stophist; + int hlinesz; + char *hline; + char *hptr; + short *chwords; + int chwordlen; + int chwordpos; + int hwgetword; + int (*hgetc) _((void)); + void (*hungetc) _((int)); + void (*hwaddc) _((int)); + void (*hwbegin) _((int)); + void (*hwend) _((void)); + void (*addtoline) _((int)); + unsigned char *cstack; + int csp; +}; + +/* Lexical analyser */ +struct lex_stack { + int dbparens; + int isfirstln; + int isfirstch; + int lexflags; + enum lextok tok; + char *tokstr; + char *zshlextext; + char *bptr; + int bsiz; + int len; + int lex_add_raw; + char *tokstr_raw; + char *bptr_raw; + int bsiz_raw; + int len_raw; + int lexstop; + zlong toklineno; +}; + +/* Parser */ +struct parse_stack { + struct heredocs *hdocs; + + int incmdpos; + int aliasspaceflag; + int incond; + int inredir; + int incasepat; + int isnewlin; + int infor; + + int eclen, ecused, ecnpats; + Wordcode ecbuf; + Eccstr ecstrs; + int ecsoffs, ecssub, ecnfunc; +}; + /************************/ /* Flags to casemodifiy */ /************************/ diff --git a/Src/zsh.mdd b/Src/zsh.mdd index 9a8c923f9..f0379d2d1 100644 --- a/Src/zsh.mdd +++ b/Src/zsh.mdd @@ -9,7 +9,8 @@ alwayslink=1 # autobins not specified because of alwayslink -objects="builtin.o compat.o cond.o exec.o glob.o hashtable.o hashnameddir.o \ +objects="builtin.o compat.o cond.o context.o \ +exec.o glob.o hashtable.o hashnameddir.o \ hist.o init.o input.o jobs.o lex.o linklist.o loop.o math.o \ mem.o module.o options.o params.o parse.o pattern.o prompt.o signals.o \ signames.o sort.o string.o subst.o text.o utils.o watch.o" -- cgit v1.2.3 From daa788d88b7935ac93a9be54691bdd56e68ae2f3 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Sat, 10 Jan 2015 10:27:01 -0800 Subject: 34212: do not change unset-ness of special parameters when exporting them --- ChangeLog | 5 +++++ Src/builtin.c | 8 ++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'Src/builtin.c') diff --git a/ChangeLog b/ChangeLog index 10556e5e9..310f47110 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-01-10 Barton E. Schaefer + + * 34212: Src/builtin.c: do not change unset-ness of special + parameters when exporting them + 2015-01-09 Barton E. Schaefer * 34202: Completion/Base/Widget/_complete_debug, diff --git a/Src/builtin.c b/Src/builtin.c index 8abe728db..8dee8f910 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -1935,7 +1935,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), * even if that's unset */ if (pm && (pm->node.flags & PM_SPECIAL)) - usepm = 1; + usepm = 2; /* indicate that we preserve the PM_UNSET flag */ /* * Don't use an existing param if @@ -2072,7 +2072,11 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), arrfixenv(pm->node.nam, x); } } - pm->node.flags = (pm->node.flags | (on & ~PM_READONLY)) & ~(off | PM_UNSET); + if (usepm == 2) /* do not change the PM_UNSET flag */ + pm->node.flags = (pm->node.flags | (on & ~PM_READONLY)) & ~off; + else + pm->node.flags = (pm->node.flags | + (on & ~PM_READONLY)) & ~(off | PM_UNSET); if (on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) { if (typeset_setwidth(cname, pm, ops, on, 0)) return NULL; -- cgit v1.2.3 From 3495dc5c275c7e3fe3517cfd20e2dc7f1cfa43db Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Sat, 10 Jan 2015 10:31:06 -0800 Subject: 34213: in previous patch, do not change usepm if it is already set --- ChangeLog | 2 +- Src/builtin.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'Src/builtin.c') diff --git a/ChangeLog b/ChangeLog index 310f47110..b102fd466 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,6 @@ 2015-01-10 Barton E. Schaefer - * 34212: Src/builtin.c: do not change unset-ness of special + * 34212, 34313: Src/builtin.c: do not change unset-ness of special parameters when exporting them 2015-01-09 Barton E. Schaefer diff --git a/Src/builtin.c b/Src/builtin.c index 8dee8f910..9258ddb6e 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -1934,7 +1934,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), * We need to compare types with an existing pm if special, * even if that's unset */ - if (pm && (pm->node.flags & PM_SPECIAL)) + if (!usepm && pm && (pm->node.flags & PM_SPECIAL)) usepm = 2; /* indicate that we preserve the PM_UNSET flag */ /* -- cgit v1.2.3 From 0e3548994ee351a317c73c88e6c83e5e9e123f9d Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Tue, 20 Jan 2015 17:31:28 +0000 Subject: 34329: add -S option to which and where --- ChangeLog | 3 +++ Doc/Zsh/builtins.yo | 4 ++-- Src/builtin.c | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) (limited to 'Src/builtin.c') diff --git a/ChangeLog b/ChangeLog index 4b6262867..da9547d2f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2015-01-20 Peter Stephenson + * 34329: Doc/Zsh/builtins.yo, Src/builtin.c: add -S option + to which and where. + * users/19756: Test/A04redirect.ztst: add test for case of closing file descriptor with no error message. diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo index 49c2c11c3..dc3937108 100644 --- a/Doc/Zsh/builtins.yo +++ b/Doc/Zsh/builtins.yo @@ -2139,11 +2139,11 @@ symlink resolved at each step might be anywhere in the path. enditem() ) findex(where) -item(tt(where) [ tt(-wpms) ] var(name) ...)( +item(tt(where) [ tt(-wpmsS) ] var(name) ...)( Equivalent to tt(whence -ca). ) findex(which) -item(tt(which) [ tt(-wpams) ] var(name) ...)( +item(tt(which) [ tt(-wpamsS) ] var(name) ...)( Equivalent to tt(whence -c). ) findex(zcompile) diff --git a/Src/builtin.c b/Src/builtin.c index 9258ddb6e..1818941b2 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -129,8 +129,8 @@ static struct builtin builtins[] = BUILTIN("unsetopt", 0, bin_setopt, 0, -1, BIN_UNSETOPT, NULL, NULL), BUILTIN("wait", 0, bin_fg, 0, -1, BIN_WAIT, NULL, NULL), BUILTIN("whence", 0, bin_whence, 0, -1, 0, "acmpvfsSw", NULL), - BUILTIN("where", 0, bin_whence, 0, -1, 0, "pmsw", "ca"), - BUILTIN("which", 0, bin_whence, 0, -1, 0, "ampsw", "c"), + BUILTIN("where", 0, bin_whence, 0, -1, 0, "pmsSw", "ca"), + BUILTIN("which", 0, bin_whence, 0, -1, 0, "ampsSw", "c"), BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "AFRILP:abcfdilmpue", NULL), BUILTIN("zcompile", 0, bin_zcompile, 0, -1, 0, "tUMRcmzka", NULL), }; -- cgit v1.2.3 From 12b813b5895cae579e403dafe43878868f27fe0f Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 22 Jan 2015 20:20:15 +0000 Subject: 34331: better handling of NULL in cd. Problem was return from symbolic link expander in weird cases where there file system isn't behaving itself properly. --- ChangeLog | 5 +++++ Src/builtin.c | 8 +++++--- Src/utils.c | 11 +++++++---- 3 files changed, 17 insertions(+), 7 deletions(-) (limited to 'Src/builtin.c') diff --git a/ChangeLog b/ChangeLog index 4b01b2ac3..9636f5c67 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-01-22 Peter Stephenson + + * 34331: Src/builtin.c, Src/utils.c: don't trip over + NULL pointer in cd in rare cases where file system goes AWOL. + 2015-01-22 Barton E. Schaefer * 34344: Test/V07pcre.ztst: fix 34338, builtins need loading too diff --git a/Src/builtin.c b/Src/builtin.c index 1818941b2..08be1acdd 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -1156,9 +1156,11 @@ cd_new_pwd(int func, LinkNode dir, int quiet) zsfree(getlinknode(dirstack)); if (chasinglinks) { - s = new_pwd; - new_pwd = findpwd(s); - zsfree(s); + s = findpwd(new_pwd); + if (s) { + zsfree(new_pwd); + new_pwd = s; + } } if (isset(PUSHDIGNOREDUPS)) { LinkNode n; diff --git a/Src/utils.c b/Src/utils.c index 4561b5e9a..cf18f1240 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -1108,10 +1108,13 @@ getnameddir(char *name) if ((pw = getpwnam(name))) { char *dir = isset(CHASELINKS) ? xsymlink(pw->pw_dir) : ztrdup(pw->pw_dir); - adduserdir(name, dir, ND_USERNAME, 1); - str = dupstring(dir); - zsfree(dir); - return str; + if (dir) { + adduserdir(name, dir, ND_USERNAME, 1); + str = dupstring(dir); + zsfree(dir); + return str; + } else + return ztrdup(pw->pw_dir); } } #endif /* HAVE_GETPWNAM */ -- cgit v1.2.3 From 2dbbc88d0b78c3fc2fb8e63fba67119c5aa456fc Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Tue, 10 Feb 2015 07:54:18 +0100 Subject: 34488: Fix use-after-free for print -zf and print -sf --- ChangeLog | 5 +++++ Src/builtin.c | 18 ++++++++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) (limited to 'Src/builtin.c') diff --git a/ChangeLog b/ChangeLog index 6729881b8..3bef21a02 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-02-10 Mikael Magnusson + + * 34488: Src/builtin.c: Fix use-after-free for print -zf and + print -sf + 2015-02-09 Peter Stephenson * 34485: Src/exec.c, Src/parse.c, Test/E01options.ztst: diff --git a/Src/builtin.c b/Src/builtin.c index 08be1acdd..e093cbe32 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -4527,7 +4527,8 @@ bin_print(char *name, char **args, Options ops, int func) if (OPT_ISSET(ops,'z') || OPT_ISSET(ops,'s')) { #ifdef HAVE_OPEN_MEMSTREAM putc(0, fout); - fflush(fout); + fclose(fout); + fout = NULL; #else rewind(fout); buf = (char *)zalloc(count + 1); @@ -4548,11 +4549,16 @@ bin_print(char *name, char **args, Options ops, int func) unqueue_signals(); } - /* Testing EBADF special-cases >&- redirections */ - if ((fout != stdout) ? (fclose(fout) != 0) : - (fflush(fout) != 0 && errno != EBADF)) { - zwarnnam(name, "write error: %e", errno); - ret = 1; +#ifdef HAVE_OPEN_MEMSTREAM + if (fout) +#endif + { + /* Testing EBADF special-cases >&- redirections */ + if ((fout != stdout) ? (fclose(fout) != 0) : + (fflush(fout) != 0 && errno != EBADF)) { + zwarnnam(name, "write error: %e", errno); + ret = 1; + } } return ret; } -- cgit v1.2.3 From 0209635832f519401ce9c45b675ef871be105cfc Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Tue, 10 Feb 2015 08:10:25 +0100 Subject: 34490: Fix leak on print -zf/-sf error --- ChangeLog | 2 ++ Src/builtin.c | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'Src/builtin.c') diff --git a/ChangeLog b/ChangeLog index 3bef21a02..cca917efe 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,8 @@ * 34488: Src/builtin.c: Fix use-after-free for print -zf and print -sf + * 34490: Src/builtin.c: Fix leak on print -zf/-sf error + 2015-02-09 Peter Stephenson * 34485: Src/exec.c, Src/parse.c, Test/E01options.ztst: diff --git a/Src/builtin.c b/Src/builtin.c index e093cbe32..c4e4b94fd 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -3732,7 +3732,7 @@ bin_print(char *name, char **args, Options ops, int func) int flen, width, prec, type, argc, n, narg, curlen = 0; int nnl = 0, fmttrunc = 0, ret = 0, maxarg = 0, nc = 0; int flags[5], *len; - char *start, *endptr, *c, *d, *flag, *buf, spec[13], *fmt = NULL; + char *start, *endptr, *c, *d, *flag, *buf = NULL, spec[13], *fmt = NULL; char **first, **argp, *curarg, *flagch = "0+- #", save = '\0', nullstr = '\0'; size_t rcount, count = 0; #ifdef HAVE_OPEN_MEMSTREAM @@ -4214,6 +4214,10 @@ bin_print(char *name, char **args, Options ops, int func) narg); if (fout != stdout) fclose(fout); +#ifdef HAVE_OPEN_MEMSTREAM + if (buf) + free(buf); +#endif return 1; } else { if (narg > maxarg) maxarg = narg; @@ -4247,6 +4251,10 @@ bin_print(char *name, char **args, Options ops, int func) narg); if (fout != stdout) fclose(fout); +#ifdef HAVE_OPEN_MEMSTREAM + if (buf) + free(buf); +#endif return 1; } else { if (narg > maxarg) maxarg = narg; @@ -4276,6 +4284,10 @@ bin_print(char *name, char **args, Options ops, int func) narg); if (fout != stdout) fclose(fout); +#ifdef HAVE_OPEN_MEMSTREAM + if (buf) + free(buf); +#endif return 1; } else { if (narg > maxarg) maxarg = narg; @@ -4431,6 +4443,10 @@ bin_print(char *name, char **args, Options ops, int func) (fflush(fout) != 0 && errno != EBADF)) { zwarnnam(name, "write error: %e", errno); } +#ifdef HAVE_OPEN_MEMSTREAM + if (buf) + free(buf); +#endif return 1; } -- cgit v1.2.3 From 2335d6254815050d3a0ae9b5a8677ec2f567b631 Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Sun, 15 Feb 2015 20:20:03 -0800 Subject: 34551: Avoid adding an extra "/" to the target path in cd_try_chdir() when the current directory is "/" --- ChangeLog | 5 +++++ Src/builtin.c | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'Src/builtin.c') diff --git a/ChangeLog b/ChangeLog index 5307eaa6d..c389b936d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-02-15 Barton E. Schaefer + + * 34551: Src/builtin.c: Avoid adding an extra "/" to the + target path in cd_try_chdir() when the current directory is "/" + 2015-02-14 Barton E. Schaefer * 34543: Src/input.c, Src/lex.c: Fix crash on garbage bytes diff --git a/Src/builtin.c b/Src/builtin.c index c4e4b94fd..614b17d7e 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -1093,9 +1093,11 @@ cd_try_chdir(char *pfix, char *dest, int hard) } else { int pfl = strlen(pfix); dlen = strlen(pwd); - + if (dlen == 1 && *pwd == '/') + dlen = 0; buf = zalloc(dlen + pfl + strlen(dest) + 3); - strcpy(buf, pwd); + if (dlen) + strcpy(buf, pwd); buf[dlen] = '/'; strcpy(buf + dlen + 1, pfix); buf[dlen + 1 + pfl] = '/'; -- cgit v1.2.3 From d4f50f2d185247b1e7e0fc7bb92d54df37558d3e Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Mon, 6 Apr 2015 10:26:57 -0700 Subject: 34851: fix thinko from 34093 that short-circuited some "whence -m" searches --- ChangeLog | 5 +++++ Src/builtin.c | 12 +++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) (limited to 'Src/builtin.c') diff --git a/ChangeLog b/ChangeLog index f570d44e3..1cb94c46c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2015-04-06 Barton E. Schaefer + + * 34851: Src/builtin.c: fix thinko from 34093 that short-circuited + some "whence -m" searches + 2015-04-03 Barton E. Schaefer * 34837: Src/glob.c: avoid loss of original file path when applying diff --git a/Src/builtin.c b/Src/builtin.c index 614b17d7e..de0101405 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -3236,21 +3236,23 @@ bin_whence(char *nam, char **argv, Options ops, int func) /* -p option is for path search only. * * We're not using it, so search for ... */ - informed = /* logical OR of what follows */ - /* aliases ... */ + informed += scanmatchtable(aliastab, pprog, 1, 0, DISABLED, - aliastab->printnode, printflags) || + aliastab->printnode, printflags); /* and reserved words ... */ + informed += scanmatchtable(reswdtab, pprog, 1, 0, DISABLED, - reswdtab->printnode, printflags) || + reswdtab->printnode, printflags); /* and shell functions... */ + informed += scanmatchtable(shfunctab, pprog, 1, 0, DISABLED, - shfunctab->printnode, printflags) || + shfunctab->printnode, printflags); /* and builtins. */ + informed += scanmatchtable(builtintab, pprog, 1, 0, DISABLED, builtintab->printnode, printflags); } -- cgit v1.2.3 From bf258a1c07a9cf1119f83d1d15310b02b94f4d67 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Wed, 29 Apr 2015 15:54:49 +0100 Subject: 34992: POSIX fix for readonly variables. With POSIXBUILTINS, variables can be marked readonly if unset. Also, variables can't have the readonly flag removed. --- ChangeLog | 7 +++++++ Doc/Zsh/builtins.yo | 7 +++++++ Src/builtin.c | 37 +++++++++++++++++++++++++++++++++---- Src/params.c | 6 +++++- Test/B02typeset.ztst | 17 +++++++++++++++++ 5 files changed, 69 insertions(+), 5 deletions(-) (limited to 'Src/builtin.c') diff --git a/ChangeLog b/ChangeLog index a5987b764..2d2fb1b5a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2015-04-29 Peter Stephenson + + * 34992: Doc/Zsh/builtins.yo, Src/builtin.c, Src/params.c, + Test/B02typeset.ztst: With POSXIBUILTINS, parameters can be + marked readonly if unset and in any case can't subsequently be + marked not readonly. + 2015-04-28 Peter Stephenson * 34989: Src/exec.c: AUTOCD needs to pass -- to cd to avoid diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo index dd5a80fe8..985d19e11 100644 --- a/Doc/Zsh/builtins.yo +++ b/Doc/Zsh/builtins.yo @@ -1933,6 +1933,13 @@ item(tt(-r))( The given var(name)s are marked readonly. Note that if var(name) is a special parameter, the readonly attribute can be turned on, but cannot then be turned off. + +If the tt(POSIX_BUILTINS) option is set, the readonly attribute is +more restrictive: unset variables can be marked readonly and cannot then +be set; furthermore, the readonly attribute cannot be removed from any +variable. Note that in zsh (unlike other shells) it is still possible +to create a local variable of the same name as this is considered a +different variable (though this variable, too, can be marked readonly). ) item(tt(-t))( Tags the named parameters. Tags have no special meaning to the shell. diff --git a/Src/builtin.c b/Src/builtin.c index de0101405..0a57489ea 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -1931,8 +1931,12 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), * locallevel as an unset one we use the pm struct anyway: that's * handled in createparam(). Here we just avoid using it for the * present tests if it's unset. + * + * POSIXBUILTINS horror: we need to retain the 'readonly' flag + * of an unset parameter. */ - usepm = pm && !(pm->node.flags & PM_UNSET); + usepm = pm && (!(pm->node.flags & PM_UNSET) || + (isset(POSIXBUILTINS) && (pm->node.flags & PM_READONLY))); /* * We need to compare types with an existing pm if special, @@ -2032,6 +2036,20 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), else if (newspecial != NS_NONE && strcmp(pname, "SECONDS") == 0) newspecial = NS_SECONDS; + if (isset(POSIXBUILTINS)) { + /* + * Stricter rules about retaining readonly attribute in this case. + */ + if ((on & PM_READONLY) && (!usepm || (pm->node.flags & PM_UNSET)) && + !value) + on |= PM_UNSET; + else if (usepm && (pm->node.flags & PM_READONLY) && + !(on & PM_READONLY)) { + zerr("read-only variable: %s", pm->node.nam); + return NULL; + } + } + /* * A parameter will be local if * 1. we are re-using an existing local parameter @@ -2078,9 +2096,15 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), } if (usepm == 2) /* do not change the PM_UNSET flag */ pm->node.flags = (pm->node.flags | (on & ~PM_READONLY)) & ~off; - else + else { + /* + * Keep unset if using readonly in POSIX mode. + */ + if (!(on & PM_READONLY) || !isset(POSIXBUILTINS)) + off |= PM_UNSET; pm->node.flags = (pm->node.flags | - (on & ~PM_READONLY)) & ~(off | PM_UNSET); + (on & ~PM_READONLY)) & ~off; + } if (on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) { if (typeset_setwidth(cname, pm, ops, on, 0)) return NULL; @@ -2256,7 +2280,12 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), * readonly flag */ pm = createparam(pname, on & ~PM_READONLY); - DPUTS(!pm, "BUG: parameter not created"); + if (!pm) { + if (on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z | + PM_INTEGER | PM_EFLOAT | PM_FFLOAT)) + zerrnam(cname, "can't change variable attribute: %s", pname); + return NULL; + } if (on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) { if (typeset_setwidth(cname, pm, ops, on, 0)) return NULL; diff --git a/Src/params.c b/Src/params.c index e8a90104c..d53b6ca7e 100644 --- a/Src/params.c +++ b/Src/params.c @@ -874,10 +874,14 @@ createparam(char *name, int flags) DPUTS(oldpm && oldpm->level > locallevel, "BUG: old local parameter not deleted"); if (oldpm && (oldpm->level == locallevel || !(flags & PM_LOCAL))) { + if (isset(POSIXBUILTINS) && (oldpm->node.flags & PM_READONLY)) { + zerr("read-only variable: %s", name); + return NULL; + } if (!(oldpm->node.flags & PM_UNSET) || (oldpm->node.flags & PM_SPECIAL)) { oldpm->node.flags &= ~PM_UNSET; if ((oldpm->node.flags & PM_SPECIAL) && oldpm->ename) { - Param altpm = + Param altpm = (Param) paramtab->getnode(paramtab, oldpm->ename); if (altpm) altpm->node.flags &= ~PM_UNSET; diff --git a/Test/B02typeset.ztst b/Test/B02typeset.ztst index 51ebc6535..f4fb8ecb9 100644 --- a/Test/B02typeset.ztst +++ b/Test/B02typeset.ztst @@ -468,3 +468,20 @@ 0:retying arrays to same array works >foo bar >goo car + + ( + setopt POSIXBUILTINS + readonly pbro + print ${+pbro} >&2 + (typeset pbro=3) + (pbro=4) + typeset -r pbro # idempotent (no error)... + print ${+pbro} >&2 # ...so still readonly... + typeset +r pbro # ...can't turn it off + ) +1:Readonly with POSIX_BUILTINS +?0 +?(eval):5: read-only variable: pbro +?(eval):6: read-only variable: pbro +?0 +?(eval):9: read-only variable: pbro -- cgit v1.2.3 From 1e6fb1a4f0586e62996bb19c9c07bc3c8d24659c Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Sun, 3 May 2015 22:34:23 +0200 Subject: Fix two bugs in typeset_setbase --- ChangeLog | 4 ++++ Src/builtin.c | 7 ++++--- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'Src/builtin.c') diff --git a/ChangeLog b/ChangeLog index ecb878ee2..c6530d875 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2015-05-04 Mikael Magnusson + + * 35021: Src/builtin.c: Fix two bugs in typeset_setbase + 2015-05-03 Peter Stephenson * 35018 (corrected): NEWS: news. diff --git a/Src/builtin.c b/Src/builtin.c index 0a57489ea..ffde5c916 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -1868,7 +1868,7 @@ typeset_setbase(const char *name, Param pm, Options ops, int on, int always) if (arg) { char *eptr; - pm->base = (int)zstrtol(arg, &eptr, 10); + int base = (int)zstrtol(arg, &eptr, 10); if (*eptr) { if (on & PM_INTEGER) zwarnnam(name, "bad base value: %s", arg); @@ -1876,11 +1876,12 @@ typeset_setbase(const char *name, Param pm, Options ops, int on, int always) zwarnnam(name, "bad precision value: %s", arg); return 1; } - if (pm->base < 2 || pm->base > 36) { + if ((on & PM_INTEGER) && (base < 2 || base > 36)) { zwarnnam(name, "invalid base (must be 2 to 36 inclusive): %d", - pm->base); + base); return 1; } + pm->base = base; } else if (always) pm->base = 0; -- cgit v1.2.3