From b4f7ccecd93ca9e64c3c3c774fdaefae83d7204a Mon Sep 17 00:00:00 2001
From: Peter Stephenson
Date: Sun, 26 Oct 2014 17:47:42 +0000
Subject: 33531 with additions: retain status of exited background jobs.
Add linked list of unwaited-for background jobs.
Truncate at value of _SC_CHILD_MAX discarding oldest.
Remove old lastpid_status mechanism for latest exited process only.
Slightly tighten safety of permanently allocated linked lists so
that this doesn't compromise signal handling.
---
Src/signals.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
(limited to 'Src/signals.c')
diff --git a/Src/signals.c b/Src/signals.c
index 2df69f96e..e72850516 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -522,14 +522,14 @@ wait_for_processes(void)
get_usage();
}
/*
- * Remember the status associated with $!, so we can
- * wait for it even if it's exited. This value is
- * only used if we can't find the PID in the job table,
- * so it doesn't matter that the value we save here isn't
- * useful until the process has exited.
+ * Accumulate a list of older jobs. We only do this for
+ * background jobs, which is something in the job table
+ * that's not marked as in the current shell or as shell builtin
+ * and is not equal to the current foreground job.
*/
- if (pn != NULL && pid == lastpid && lastpid_status != -1L)
- lastpid_status = lastval2;
+ if (jn && !(jn->stat & (STAT_CURSH|STAT_BUILTIN)) &&
+ jn - jobtab != thisjob)
+ addbgstatus(pid, (int)lastval2);
}
}
--
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/signals.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 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/signals.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