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(-)
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 1.4.1