From b5198b10a1d1b6a15c583eecf12fda0c08b19ad6 Mon Sep 17 00:00:00 2001
From: Peter Stephenson
Date: Fri, 13 Jun 2014 21:39:44 +0100
Subject: 32768 with further modifications: LOCAL_LOOPS option.
---
ChangeLog | 6 ++++++
Doc/Zsh/options.yo | 23 +++++++++++++++++++----
Src/exec.c | 17 +++++++++++++++--
Src/options.c | 1 +
Src/zsh.h | 1 +
Test/E01options.ztst | 44 +++++++++++++++++++++++++++++++++++++++++++-
Test/ztst.zsh | 6 +++++-
7 files changed, 90 insertions(+), 8 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 2b689b71d..6c4355e2f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
2014-06-13 Peter Stephenson
+ * 32768, with further modifications: Doc/Zsh/options.yo,
+ Src/exec.c, Src/options.c, Src/zsh.h, Test/E01options.ztst,
+ Test/ztst.zsh: LOCAL_LOOPS option to restrict effect of
+ continue and break in function scope.
+
* 32666: Doc/Zsh/compat.yo: shell emulation based on executable
name incompletely documented.
@@ -18,6 +23,7 @@
* Jun T: 32755: Doc/Zsh/grammar.yo: move line that was in the
wrong place.
+
2014-06-07 Barton E. Schaefer
* Nikolas Garofil: 32737: Src/utils.c: properly ifdef declarations
diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index 7788cd755..9cb385e49 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -1631,6 +1631,21 @@ tt(FUNCTION_ARGZERO) from on to off (or off to on) does not change the
current value of tt($0). Only the state upon entry to the function or
script has an effect. Compare tt(POSIX_ARGZERO).
)
+pindex(LOCAL_LOOPS)
+pindex(NO_LOCAL_LOOPS)
+pindex(LOCALLOOPS)
+pindex(NOLOCALLOOPS)
+cindex(break, inside function)
+cindex(continue, inside function)
+cinde(function, scope of break and continue)
+item(tt(LOCAL_LOOPS))(
+When this option is not set, the effect of tt(break) and tt(continue)
+commands may propagate outside function scope, affecting loops in
+calling functions. When the option is set in a calling function, a
+tt(break) or a tt(continue) that is not caught within a called function
+(regardless of the setting of the option within that function)
+produces a warning and the effect is cancelled.
+)
pindex(LOCAL_OPTIONS)
pindex(NO_LOCAL_OPTIONS)
pindex(LOCALOPTIONS)
@@ -1639,10 +1654,10 @@ item(tt(LOCAL_OPTIONS) )(
If this option is set at the point of return from a shell function,
most options (including this one) which were in force upon entry to
the function are restored; options that are not restored are
-tt(PRIVILEGED) and tt(RESTRICTED). Otherwise, only this option and the
-tt(XTRACE) and tt(PRINT_EXIT_VALUE) options are restored. Hence
-if this is explicitly unset by a shell function the other options in
-force at the point of return will remain so.
+tt(PRIVILEGED) and tt(RESTRICTED). Otherwise, only this option,
+and the tt(LOCAL_LOOPS), tt(XTRACE) and tt(PRINT_EXIT_VALUE) options are
+restored. Hence if this is explicitly unset by a shell function the
+other options in force at the point of return will remain so.
A shell function can also guarantee itself a known shell configuration
with a formulation like `tt(emulate -L zsh)'; the tt(-L) activates
tt(LOCAL_OPTIONS).
diff --git a/Src/exec.c b/Src/exec.c
index 8249deff2..5ad957f98 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -4614,7 +4614,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
char *name = shfunc->node.nam;
int flags = shfunc->node.flags, ooflags;
char *fname = dupstring(name);
- int obreaks, saveemulation, restore_sticky;
+ int obreaks, ocontflag, oloops, saveemulation, restore_sticky;
Eprog prog;
struct funcstack fstack;
static int oflags;
@@ -4626,7 +4626,9 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
pushheap();
oargv0 = NULL;
- obreaks = breaks;;
+ obreaks = breaks;
+ ocontflag = contflag;
+ oloops = loops;
if (trap_state == TRAP_STATE_PRIMED)
trap_return--;
oldlastval = lastval;
@@ -4814,6 +4816,17 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
opts[XTRACE] = saveopts[XTRACE];
opts[PRINTEXITVALUE] = saveopts[PRINTEXITVALUE];
opts[LOCALOPTIONS] = saveopts[LOCALOPTIONS];
+ opts[LOCALLOOPS] = saveopts[LOCALLOOPS];
+ }
+
+ if (opts[LOCALLOOPS]) {
+ if (contflag)
+ zwarn("`continue' active at end of function scope");
+ if (breaks)
+ zwarn("`break' active at end of function scope");
+ breaks = obreaks;
+ contflag = ocontflag;
+ loops = oloops;
}
endtrapscope();
diff --git a/Src/options.c b/Src/options.c
index 2163bff4d..6e4e7b911 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -180,6 +180,7 @@ static struct optname optns[] = {
{{NULL, "listrowsfirst", 0}, LISTROWSFIRST},
{{NULL, "listtypes", OPT_ALL}, LISTTYPES},
{{NULL, "localoptions", OPT_EMULATE|OPT_KSH}, LOCALOPTIONS},
+{{NULL, "localloops", OPT_EMULATE}, LOCALLOOPS},
{{NULL, "localpatterns", OPT_EMULATE}, LOCALPATTERNS},
{{NULL, "localtraps", OPT_EMULATE|OPT_KSH}, LOCALTRAPS},
{{NULL, "login", OPT_SPECIAL}, LOGINSHELL},
diff --git a/Src/zsh.h b/Src/zsh.h
index 05d582cda..fa7396112 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -2129,6 +2129,7 @@ enum {
LISTPACKED,
LISTROWSFIRST,
LISTTYPES,
+ LOCALLOOPS,
LOCALOPTIONS,
LOCALPATTERNS,
LOCALTRAPS,
diff --git a/Test/E01options.ztst b/Test/E01options.ztst
index d9f219115..46b183776 100644
--- a/Test/E01options.ztst
+++ b/Test/E01options.ztst
@@ -430,7 +430,7 @@
foo
unfunction foo
0:FUNCTION_ARGZERO option
->My name is ZTST_execchunk
+>My name is (anon)
>My name is foo
setopt _NO_glob_
@@ -1114,3 +1114,45 @@
>1
>1
>2
+
+ for (( i = 0; i < 10; i++ )); do
+ () {
+ print $i
+ break
+ }
+ done
+0:NO_LOCAL_LOOPS
+>0
+
+ () {
+ emulate -L zsh
+ setopt localloops
+ for (( i = 0; i < 10; i++ )); do
+ () {
+ setopt nolocalloops # ignored in parent
+ print $i
+ break
+ }
+ done
+ }
+0:LOCAL_LOOPS
+>0
+>1
+>2
+>3
+>4
+>5
+>6
+>7
+>8
+>9
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
+?(anon):4: `break' active at end of function scope
diff --git a/Test/ztst.zsh b/Test/ztst.zsh
index 745a13cff..74111f6cc 100755
--- a/Test/ztst.zsh
+++ b/Test/ztst.zsh
@@ -260,8 +260,12 @@ $ZTST_redir"
# Execute an indented chunk. Redirections will already have
# been set up, but we need to handle the options.
ZTST_execchunk() {
+ setopt localloops # don't let continue & break propagate out
options=($ZTST_testopts)
- eval "$ZTST_code"
+ () {
+ unsetopt localloops
+ eval "$ZTST_code"
+ }
ZTST_status=$?
# careful... ksh_arrays may be in effect.
ZTST_testopts=(${(kv)options[*]})
--
cgit v1.2.3