NetBSD Problem Report #48843
From jarmo.jaakkola@roskakori.fi Wed May 28 23:08:59 2014
Return-Path: <jarmo.jaakkola@roskakori.fi>
Received: from mail.netbsd.org (mail.netbsd.org [149.20.53.66])
(using TLSv1 with cipher ECDHE-RSA-AES256-SHA (256/256 bits))
(Client CN "mail.netbsd.org", Issuer "Postmaster NetBSD.org" (verified OK))
by mollari.NetBSD.org (Postfix) with ESMTPS id 3C778A6516
for <gnats-bugs@gnats.NetBSD.org>; Wed, 28 May 2014 23:08:59 +0000 (UTC)
Message-Id: <20140528230853.5CE54530F@roskakori.fi>
Date: Thu, 29 May 2014 02:08:53 +0300 (EEST)
From: Jarmo Jaakkola <jarmo.jaakkola@roskakori.fi>
Reply-To: Jarmo Jaakkola <jarmo.jaakkola@roskakori.fi>
To: gnats-bugs@gnats.NetBSD.org
Subject: sh(1): break/continue/return broken inside dot commands
X-Send-Pr-Version: 3.95
>Number: 48843
>Category: bin
>Synopsis: dot commands mess up scope nesting tracking
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: bin-bug-people
>State: closed
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Wed May 28 23:10:00 +0000 2014
>Closed-Date: Mon Oct 31 05:33:09 +0000 2016
>Last-Modified: Mon Oct 31 05:33:09 +0000 2016
>Originator: Jarmo Jaakkola
>Release: NetBSD 6.1.2_PATCH
>Organization:
>Environment:
System: NetBSD kotoisa.roskakori.fi 6.1.2_PATCH NetBSD 6.1.2_PATCH (KOTOISA) #5: Mon Jan 20 17:01:44 EET 2014 jammuli@kotoisa.roskakori.fi:/usr/src/sys/arch/amd64/compile/KOTOISA amd64
Architecture: x86_64
Machine: amd64
>Description:
Evaluation of commands goes completely haywire if a file containing
a break/continue/return command outside its "intended" scope is sourced
using a dot command inside its "intended" scope. The main symptom is
not exiting from the sourced file when supposed to, leading to evaluation
of commands that were not supposed to be evaluated. A secondary symptom
is that these extra commands are not evaluated correctly, as some of them
are skipped. Some examples are listed in the How-To-Repeat section.
According to the POSIX standard, this is how it should work:
dot:
The shell shall execute commands from the file in the current
environment.
break:
The break utility shall exit from the smallest enclosing for, while,
or until loop, [...]
continue:
The continue utility shall return to the top of the smallest
enclosing for, while, or until loop, [...]
return:
The return utility shall cause the shell to stop executing
the current function or dot script. If the shell is not currently
executing a function or dot script, the results are unspecified.
It is clear that return should return from a sourced file, which
it does not do. Whether break and continue should work from the sourced
file might be debatable. Because the dot command says "in the current
environment", I'd say yes. In any case, it should not fail in weird
ways like it does now!
The problems occur with return (a) and break/continue (b) because:
1) dotcmd() does not record the function nesting level prior to
sourcing the file nor does it touch the loopnest variable,
leading to either
2 a) returncmd() being unable to detect that it should not set
evalskip to SKIPFUNC but SKIPFILE, or
b) breakcmd() setting evalskip to SKIPCONT or SKIPBREAK,
leading to
3) cmdloop() not detecting that it should skip the rest of
the file, due to only checking for SKIPFILE.
The result is that cmdloop() keeps executing lines from the file
whilst evalskip is set, which is the main symptom. Because
evalskip is checked in multiple places in eval.c, the secondary
symptom appears.
>How-To-Repeat:
Run the following script:
printf "break\necho break1; echo break2" >break
printf "continue\necho continue1; echo continue2" >continue
printf "return\necho return1; echo return2" >return
while true; do . ./break; done
for i in 1 2; do . ./continue; done
func() {
. ./return
}
func
No output should be produced, but instead this is the result:
break1
continue1
continue1
return1
The main symptom is evident from the unexpected output and the secondary
one from the fact that there are no lines with '2' in them.
>Fix:
Here is patch to src/bin/sh to fix the above problems. It keeps
track of the function nesting level at the beginning of a dot command
to enable the return command to work properly.
I also changed the undefined-by-standard functionality of the return
command when it's not in a dot command or function from (indirectly)
exiting the shell to being silently ignored. This was done because
the previous way has at least one bug: the shell exits without asking
for confirmation when there are stopped jobs.
Because I read the standard to mean that break and continue should have
an effect outside the sourced file, that's how I implemented it. For what
it's worth, this also seems to be what bash does. Also laziness, because
this way required no changes to loopnesting tracking. If this is not
wanted, it might make sense to move the nesting tracking to the inputfile
stack.
The patch also does some clean-up to reduce the amount of global
variables by moving the dotcmd() and the find_dot_file() functions from
main.c to eval.c and making in_function() a proper function.
Index: bin/sh/eval.c
===================================================================
RCS file: /cvsroot/src/bin/sh/eval.c,v
retrieving revision 1.103
diff -u -p -u -r1.103 eval.c
--- bin/sh/eval.c 14 Nov 2011 18:24:45 -0000 1.103
+++ bin/sh/eval.c 28 May 2014 22:51:38 -0000
@@ -88,11 +88,20 @@ __RCSID("$NetBSD: eval.c,v 1.103 2011/11
#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
#define EV_BACKCMD 04 /* command executing within back quotes */
-int evalskip; /* set if we are skipping commands */
+STATIC enum skipstate evalskip; /* != SKIPNONE if we are skipping commands */
STATIC int skipcount; /* number of levels to skip */
-MKINIT int loopnest; /* current loop nesting level */
-int funcnest; /* depth of function calls */
+STATIC int loopnest; /* current loop nesting level */
+STATIC int funcnest; /* depth of function calls */
STATIC int builtin_flags; /* evalcommand flags for builtins */
+/*
+ * Base function nesting level inside a dot command. Set to 0 initially
+ * and to (funcnest + 1) before every dot command to enable
+ * 1) detection of being in a file sourced by a dot command and
+ * 2) counting of function nesting in that file for the implementation
+ * of the return command.
+ * The value is reset to its previous value after the dot command.
+ */
+STATIC int dot_funcnest;
const char *commandname;
@@ -110,6 +119,7 @@ STATIC void evalpipe(union node *);
STATIC void evalcommand(union node *, int, struct backcmd *);
STATIC void prehash(union node *);
+STATIC char *find_dot_file(char *);
/*
* Called to reset things after an exception.
@@ -119,9 +129,7 @@ STATIC void prehash(union node *);
INCLUDE "eval.h"
RESET {
- evalskip = 0;
- loopnest = 0;
- funcnest = 0;
+ reset_eval();
}
SHELLPROC {
@@ -129,6 +137,15 @@ SHELLPROC {
}
#endif
+void
+reset_eval(void)
+{
+ evalskip = SKIPNONE;
+ dot_funcnest = 0;
+ loopnest = 0;
+ funcnest = 0;
+}
+
static int
sh_pipe(int fds[2])
{
@@ -326,11 +343,11 @@ evalloop(union node *n, int flags)
evaltree(n->nbinary.ch1, EV_TESTED);
if (evalskip) {
skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
- evalskip = 0;
+ evalskip = SKIPNONE;
continue;
}
if (evalskip == SKIPBREAK && --skipcount <= 0)
- evalskip = 0;
+ evalskip = SKIPNONE;
break;
}
if (n->type == NWHILE) {
@@ -376,11 +393,11 @@ evalfor(union node *n, int flags)
status = exitstatus;
if (evalskip) {
if (evalskip == SKIPCONT && --skipcount <= 0) {
- evalskip = 0;
+ evalskip = SKIPNONE;
continue;
}
if (evalskip == SKIPBREAK && --skipcount <= 0)
- evalskip = 0;
+ evalskip = SKIPNONE;
break;
}
}
@@ -961,7 +978,7 @@ normal_fork:
popredir();
INTON;
if (evalskip == SKIPFUNC) {
- evalskip = 0;
+ evalskip = SKIPNONE;
skipcount = 0;
}
if (flags & EV_EXIT)
@@ -1102,7 +1119,24 @@ prehash(union node *n)
pathval());
}
+STATIC int
+in_function(void)
+{
+ return funcnest;
+}
+
+STATIC enum skipstate
+current_skipstate(void)
+{
+ return evalskip;
+}
+STATIC void
+stop_skipping(void)
+{
+ evalskip = SKIPNONE;
+ skipcount = 0;
+}
/*
* Builtin commands. Builtin commands whose functions are closely
@@ -1149,9 +1183,84 @@ breakcmd(int argc, char **argv)
return 0;
}
+int
+dotcmd(int argc, char **argv)
+{
+ exitstatus = 0;
+
+ if (argc >= 2) { /* That's what SVR2 does */
+ char *fullname;
+ /*
+ * dot_funcnest needs to be 0 when not in a dotcmd, so it
+ * cannot be restored with (funcnest + 1).
+ */
+ int dot_funcnest_old;
+ struct stackmark smark;
+
+ setstackmark(&smark);
+ fullname = find_dot_file(argv[1]);
+ setinputfile(fullname, 1);
+ commandname = fullname;
+ dot_funcnest_old = dot_funcnest;
+ dot_funcnest = funcnest + 1;
+ cmdloop(0);
+ dot_funcnest = dot_funcnest_old;
+ popfile();
+ popstackmark(&smark);
+ }
+ return exitstatus;
+}
+
+/*
+ * Take commands from a file. To be compatible we should do a path
+ * search for the file, which is necessary to find sub-commands.
+ */
+
+STATIC char *
+find_dot_file(char *basename)
+{
+ char *fullname;
+ const char *path = pathval();
+ struct stat statb;
+
+ /* don't try this for absolute or relative paths */
+ if (strchr(basename, '/'))
+ return basename;
+
+ while ((fullname = padvance(&path, basename)) != NULL) {
+ if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
+ /*
+ * Don't bother freeing here, since it will
+ * be freed by the caller.
+ */
+ return fullname;
+ }
+ stunalloc(fullname);
+ }
+
+ /* not found in the PATH */
+ error("%s: not found", basename);
+ /* NOTREACHED */
+}
+
+
/*
* The return command.
+ *
+ * Quoth the POSIX standard:
+ * The return utility shall cause the shell to stop executing the current
+ * function or dot script. If the shell is not currently executing
+ * a function or dot script, the results are unspecified.
+ *
+ * As for the unspecified part, there seems to be no de-facto standard: bash
+ * ignores the return with a warning, zsh ignores the return in interactive
+ * mode but seems to liken it to exit in a script. (checked May 2014)
+ *
+ * We choose to silently ignore the return. Older versions of this shell
+ * set evalskip to SKIPFILE causing the shell to (indirectly) exit. This
+ * had at least the problem of circumventing the check for stopped jobs,
+ * which would occur for exit or ^D.
*/
int
@@ -1159,17 +1268,19 @@ returncmd(int argc, char **argv)
{
int ret = argc > 1 ? number(argv[1]) : exitstatus;
- if (funcnest) {
+ if ((dot_funcnest == 0 && funcnest)
+ || (dot_funcnest > 0 && funcnest - (dot_funcnest - 1) > 0)) {
evalskip = SKIPFUNC;
skipcount = 1;
- return ret;
- }
- else {
- /* Do what ksh does; skip the rest of the file */
+ } else if (dot_funcnest > 0) {
evalskip = SKIPFILE;
skipcount = 1;
- return ret;
+ } else {
+ /* XXX: should a warning be issued? */
+ ret = 0;
}
+
+ return ret;
}
Index: bin/sh/eval.h
===================================================================
RCS file: /cvsroot/src/bin/sh/eval.h,v
retrieving revision 1.15
diff -u -p -u -r1.15 eval.h
--- bin/sh/eval.h 15 Feb 2008 17:26:06 -0000 1.15
+++ bin/sh/eval.h 28 May 2014 22:51:38 -0000
@@ -53,12 +53,21 @@ void evaltree(union node *, int);
void evalbackcmd(union node *, struct backcmd *);
/* in_function returns nonzero if we are currently evaluating a function */
-#define in_function() funcnest
-extern int funcnest;
-extern int evalskip;
+int in_function(void); /* return non-zero, if evaluating a function */
/* reasons for skipping commands (see comment on breakcmd routine) */
-#define SKIPBREAK 1
-#define SKIPCONT 2
-#define SKIPFUNC 3
-#define SKIPFILE 4
+enum skipstate {
+ SKIPNONE = 0, /* not skipping */
+ SKIPBREAK, /* break */
+ SKIPCONT, /* continue */
+ SKIPFUNC, /* return in a function */
+ SKIPFILE /* return in a dot command */
+};
+
+enum skipstate current_skipstate(void);
+void stop_skipping(void); /* reset internal skipping state to SKIPNONE */
+
+/*
+ * Only for use by reset() in init.c!
+ */
+void reset_eval(void);
Index: bin/sh/main.c
===================================================================
RCS file: /cvsroot/src/bin/sh/main.c,v
retrieving revision 1.57
diff -u -p -u -r1.57 main.c
--- bin/sh/main.c 18 Jun 2011 21:18:46 -0000 1.57
+++ bin/sh/main.c 28 May 2014 22:51:38 -0000
@@ -89,7 +89,6 @@ extern int etext();
#endif
STATIC void read_profile(const char *);
-STATIC char *find_dot_file(char *);
int main(int, char **);
/*
@@ -239,6 +238,7 @@ cmdloop(int top)
struct stackmark smark;
int inter;
int numeof = 0;
+ enum skipstate skip;
TRACE(("cmdloop(%d) called\n", top));
setstackmark(&smark);
@@ -270,8 +270,18 @@ cmdloop(int top)
}
popstackmark(&smark);
setstackmark(&smark);
- if (evalskip == SKIPFILE) {
- evalskip = 0;
+
+ /*
+ * Any SKIP* can occur here! SKIP(FUNC|BREAK|CONT) occur when
+ * a dotcmd is in a loop or a function body and appropriate
+ * built-ins occurs in file scope in the sourced file. Values
+ * other than SKIPFILE are reset by the appropriate eval*()
+ * that contained the dotcmd() call.
+ */
+ skip = current_skipstate();
+ if (skip != SKIPNONE) {
+ if (skip == SKIPFILE)
+ stop_skipping();
break;
}
}
@@ -337,60 +347,6 @@ readcmdfile(char *name)
-/*
- * Take commands from a file. To be compatible we should do a path
- * search for the file, which is necessary to find sub-commands.
- */
-
-
-STATIC char *
-find_dot_file(char *basename)
-{
- char *fullname;
- const char *path = pathval();
- struct stat statb;
-
- /* don't try this for absolute or relative paths */
- if (strchr(basename, '/'))
- return basename;
-
- while ((fullname = padvance(&path, basename)) != NULL) {
- if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
- /*
- * Don't bother freeing here, since it will
- * be freed by the caller.
- */
- return fullname;
- }
- stunalloc(fullname);
- }
-
- /* not found in the PATH */
- error("%s: not found", basename);
- /* NOTREACHED */
-}
-
-int
-dotcmd(int argc, char **argv)
-{
- exitstatus = 0;
-
- if (argc >= 2) { /* That's what SVR2 does */
- char *fullname;
- struct stackmark smark;
-
- setstackmark(&smark);
- fullname = find_dot_file(argv[1]);
- setinputfile(fullname, 1);
- commandname = fullname;
- cmdloop(0);
- popfile();
- popstackmark(&smark);
- }
- return exitstatus;
-}
-
-
int
exitcmd(int argc, char **argv)
{
Index: bin/sh/sh.1
===================================================================
RCS file: /cvsroot/src/bin/sh/sh.1,v
retrieving revision 1.106
diff -u -p -u -r1.106 sh.1
--- bin/sh/sh.1 5 Oct 2011 13:15:30 -0000 1.106
+++ bin/sh/sh.1 28 May 2014 22:51:38 -0000
@@ -1179,10 +1179,23 @@ be built in for efficiency (e.g.
.Xr test 1 ,
etc).
.Bl -tag -width 5n
-.It :
+.It : [ Ar arg ... ]
A null command that returns a 0 (true) exit value.
+Any arguments are ignored.
.It \&. file
-The commands in the specified file are read and executed by the shell.
+The dot command reads and executes the commands from the specified
+.Ar file
+in the current shell environment.
+The file does not need to be executable and is looked up from the directories
+listed in the
+.Ev PATH
+variable if it does not contain a directory separator
+.Pq Sq / .
+The return command can be used for a premature return from the sourced file.
+.Pp
+A non-obvious consequence of the file executing in the current environment
+is that loop control keywords (continue and break) can be used in the file
+to control loops surrounding the dot command.
.It alias Op Ar name Ns Op Ar "=string ..."
If
.Ar name=string
@@ -1620,6 +1633,19 @@ With the
.Fl p
option specified the output will be formatted suitably for non-interactive use.
.Pp
+.It return [ Ar n ]
+Stop executing the current function or a dot command with return value of
+.Ar n
+or the value of the last executed command, if not specified.
+For portability,
+.Ar n
+should be in the range from 0 to 255.
+.Pp
+The effects of using a return command outside a function or a dot command
+are not standardized.
+This implementation (currently) treats such a return as a no-op with
+a return value of 0 (success, true).
+Use the exit command if you want to return from a script or exit your shell.
.It set Oo { Fl options | Cm +options | Cm \-- } Oc Ar arg ...
The
.Ic set
>Release-Note:
>Audit-Trail:
From: Jarmo Jaakkola <jarmo.jaakkola@roskakori.fi>
To: gnats-bugs@NetBSD.org
Cc:
Subject: Re: bin/48843: sh(1): break/continue/return broken inside dot
commands
Date: Thu, 29 May 2014 03:03:40 +0300
Because of this bug, the package devel/git is broken: PR pkg/48844.
--
Jarmo Jaakkola
From: Jarmo Jaakkola <jarmo.jaakkola@roskakori.fi>
To: gnats-bugs@NetBSD.org
Cc:
Subject: Re: bin/48843: sh(1): break/continue/return broken inside dot
commands
Date: Thu, 29 May 2014 03:26:45 +0300
Here's a bunch test cases.
The test cases are named with the pattern
dotscope_cmd_cmdscope,
where dotscope is the scope in which the dot command is and cmdscope
is the scope where cmd is in the sourced file.
These cases fail for the current shell and are fixed by the original
patch:
t_dotcmd:for_break_case, t_dotcmd:for_break_file,
t_dotcmd:for_break_func, t_dotcmd:for_continue_case,
t_dotcmd:for_continue_file, t_dotcmd:for_continue_func,
t_dotcmd:func_return_case, t_dotcmd:func_return_compound,
t_dotcmd:func_return_file, t_dotcmd:func_return_for,
t_dotcmd:func_return_until, t_dotcmd:func_return_while,
t_dotcmd:until_break_case, t_dotcmd:until_break_file,
t_dotcmd:until_break_func, t_dotcmd:until_continue_case,
t_dotcmd:until_continue_file, t_dotcmd:until_continue_func,
t_dotcmd:while_break_case, t_dotcmd:while_break_file,
t_dotcmd:while_break_func, t_dotcmd:while_continue_case,
t_dotcmd:while_continue_file, t_dotcmd:while_continue_func
Index: etc/mtree/NetBSD.dist.tests
===================================================================
RCS file: /cvsroot/src/etc/mtree/NetBSD.dist.tests,v
retrieving revision 1.60
diff -u -p -u -r1.60 NetBSD.dist.tests
--- etc/mtree/NetBSD.dist.tests 13 Feb 2012 21:03:06 -0000 1.60
+++ etc/mtree/NetBSD.dist.tests 28 May 2014 23:59:58 -0000
@@ -128,6 +128,10 @@
./usr/tests/atf/atf-run
./usr/tests/atf/atf-sh
./usr/tests/atf/test-programs
+./usr/tests/bin
+./usr/tests/bin/sh
+./usr/tests/bin/sh/dotcmd
+./usr/tests/bin/sh/dotcmd/out
./usr/tests/crypto
./usr/tests/crypto/libcrypto
./usr/tests/dev
diff -urN nonexistant/Makefile tests/bin/Makefile
--- nonexistant/Makefile 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/Makefile 2014-05-27 14:45:36.000000000 +0300
@@ -0,0 +1,10 @@
+# $NetBSD$
+#
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/bin
+
+TESTS_SUBDIRS+= sh
+
+.include <bsd.test.mk>
Binary files nonexistant/sh/.Makefile.swp and tests/bin/sh/.Makefile.swp differ
diff -urN nonexistant/sh/Makefile tests/bin/sh/Makefile
--- nonexistant/sh/Makefile 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/Makefile 2014-05-27 23:51:40.000000000 +0300
@@ -0,0 +1,10 @@
+# $NetBSD$
+#
+
+.include <bsd.own.mk>
+
+TESTSDIR = ${TESTSBASE}/bin/sh
+
+TESTS_SUBDIRS += dotcmd
+
+.include <bsd.test.mk>
Binary files nonexistant/sh/dotcmd/.Makefile.swp and tests/bin/sh/dotcmd/.Makefile.swp differ
Binary files nonexistant/sh/dotcmd/.t_dotcmd.sh.swp and tests/bin/sh/dotcmd/.t_dotcmd.sh.swp differ
diff -urN nonexistant/sh/dotcmd/Makefile tests/bin/sh/dotcmd/Makefile
--- nonexistant/sh/dotcmd/Makefile 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/Makefile 2014-05-28 13:29:14.000000000 +0300
@@ -0,0 +1,40 @@
+# $NetBSD$
+#
+
+.include <bsd.own.mk>
+
+TESTSDIR = ${TESTSBASE}/bin/sh/dotcmd
+
+TESTS_SH = t_dotcmd
+
+FILESDIR = ${TESTSDIR}/out
+
+# Testing scripts: dotcmd in various scopes includes a file with
+# return / break / continue in various scopes.
+#
+.for cmd_scope in case compound file for func subshell until while
+. for cmd in return break continue
+FILES += ${cmd}_${cmd_scope}
+FILESDIR_${cmd}_${cmd_scope} = ${TESTSDIR}
+FILESBUILD_${cmd}_${cmd_scope} = yes
+
+${cmd}_${cmd_scope}: scoped_command
+ ${.CURDIR}/scoped_command '${cmd_scope}' '${cmd}' '${cmd}' \
+ >'${.TARGET}'
+
+. for dot_scope in case compound file for func subshell until while
+FILES += \
+ ${dot_scope}_${cmd}_${cmd_scope} \
+ out/${dot_scope}_${cmd}_${cmd_scope}.out
+FILESDIR_${dot_scope}_${cmd}_${cmd_scope} = ${TESTSDIR}
+FILESBUILD_${dot_scope}_${cmd}_${cmd_scope} = yes
+FILESMODE_${dot_scope}_${cmd}_${cmd_scope} = ${BINMODE}
+
+${dot_scope}_${cmd}_${cmd_scope}: scoped_command
+ ${.CURDIR}/scoped_command '${dot_scope}' \
+ '. "${cmd}_${cmd_scope}"' 'dotcmd' 'dotcmd' >'${.TARGET}'
+. endfor
+. endfor
+.endfor
+
+.include <bsd.test.mk>
diff -urN nonexistant/sh/dotcmd/out/case_break_case.out tests/bin/sh/dotcmd/out/case_break_case.out
--- nonexistant/sh/dotcmd/out/case_break_case.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/case_break_case.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+before case
+before dotcmd
+before case
+before break
+after break, return value: 0
+after case
+after dotcmd, return value: 0
+after case
diff -urN nonexistant/sh/dotcmd/out/case_break_compound.out tests/bin/sh/dotcmd/out/case_break_compound.out
--- nonexistant/sh/dotcmd/out/case_break_compound.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/case_break_compound.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+before case
+before dotcmd
+compound start
+before break
+after break, return value: 0
+compound end
+after dotcmd, return value: 0
+after case
diff -urN nonexistant/sh/dotcmd/out/case_break_file.out tests/bin/sh/dotcmd/out/case_break_file.out
--- nonexistant/sh/dotcmd/out/case_break_file.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/case_break_file.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+before case
+before dotcmd
+before break
+after break, return value: 0
+after dotcmd, return value: 0
+after case
diff -urN nonexistant/sh/dotcmd/out/case_break_for.out tests/bin/sh/dotcmd/out/case_break_for.out
--- nonexistant/sh/dotcmd/out/case_break_for.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/case_break_for.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,7 @@
+before case
+before dotcmd
+before for
+before break
+after for
+after dotcmd, return value: 0
+after case
diff -urN nonexistant/sh/dotcmd/out/case_break_func.out tests/bin/sh/dotcmd/out/case_break_func.out
--- nonexistant/sh/dotcmd/out/case_break_func.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/case_break_func.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+before case
+before dotcmd
+before function
+before break
+after break
+after function
+after dotcmd, return value: 0
+after case
diff -urN nonexistant/sh/dotcmd/out/case_break_subshell.out tests/bin/sh/dotcmd/out/case_break_subshell.out
--- nonexistant/sh/dotcmd/out/case_break_subshell.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/case_break_subshell.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+before case
+before dotcmd
+subshell start
+before break
+after break, return value: 0
+subshell end
+after dotcmd, return value: 0
+after case
diff -urN nonexistant/sh/dotcmd/out/case_break_until.out tests/bin/sh/dotcmd/out/case_break_until.out
--- nonexistant/sh/dotcmd/out/case_break_until.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/case_break_until.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,7 @@
+before case
+before dotcmd
+before until
+before break
+after until
+after dotcmd, return value: 0
+after case
diff -urN nonexistant/sh/dotcmd/out/case_break_while.out tests/bin/sh/dotcmd/out/case_break_while.out
--- nonexistant/sh/dotcmd/out/case_break_while.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/case_break_while.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,7 @@
+before case
+before dotcmd
+before while
+before break
+after while
+after dotcmd, return value: 0
+after case
diff -urN nonexistant/sh/dotcmd/out/case_continue_case.out tests/bin/sh/dotcmd/out/case_continue_case.out
--- nonexistant/sh/dotcmd/out/case_continue_case.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/case_continue_case.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+before case
+before dotcmd
+before case
+before continue
+after continue, return value: 0
+after case
+after dotcmd, return value: 0
+after case
diff -urN nonexistant/sh/dotcmd/out/case_continue_compound.out tests/bin/sh/dotcmd/out/case_continue_compound.out
--- nonexistant/sh/dotcmd/out/case_continue_compound.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/case_continue_compound.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+before case
+before dotcmd
+compound start
+before continue
+after continue, return value: 0
+compound end
+after dotcmd, return value: 0
+after case
diff -urN nonexistant/sh/dotcmd/out/case_continue_file.out tests/bin/sh/dotcmd/out/case_continue_file.out
--- nonexistant/sh/dotcmd/out/case_continue_file.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/case_continue_file.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+before case
+before dotcmd
+before continue
+after continue, return value: 0
+after dotcmd, return value: 0
+after case
diff -urN nonexistant/sh/dotcmd/out/case_continue_for.out tests/bin/sh/dotcmd/out/case_continue_for.out
--- nonexistant/sh/dotcmd/out/case_continue_for.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/case_continue_for.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+before case
+before dotcmd
+before for
+before continue
+before continue
+after for
+after dotcmd, return value: 0
+after case
diff -urN nonexistant/sh/dotcmd/out/case_continue_func.out tests/bin/sh/dotcmd/out/case_continue_func.out
--- nonexistant/sh/dotcmd/out/case_continue_func.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/case_continue_func.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+before case
+before dotcmd
+before function
+before continue
+after continue
+after function
+after dotcmd, return value: 0
+after case
diff -urN nonexistant/sh/dotcmd/out/case_continue_subshell.out tests/bin/sh/dotcmd/out/case_continue_subshell.out
--- nonexistant/sh/dotcmd/out/case_continue_subshell.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/case_continue_subshell.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+before case
+before dotcmd
+subshell start
+before continue
+after continue, return value: 0
+subshell end
+after dotcmd, return value: 0
+after case
diff -urN nonexistant/sh/dotcmd/out/case_continue_until.out tests/bin/sh/dotcmd/out/case_continue_until.out
--- nonexistant/sh/dotcmd/out/case_continue_until.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/case_continue_until.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+before case
+before dotcmd
+before until
+before continue
+before continue
+after until
+after dotcmd, return value: 0
+after case
diff -urN nonexistant/sh/dotcmd/out/case_continue_while.out tests/bin/sh/dotcmd/out/case_continue_while.out
--- nonexistant/sh/dotcmd/out/case_continue_while.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/case_continue_while.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+before case
+before dotcmd
+before while
+before continue
+before continue
+after while
+after dotcmd, return value: 0
+after case
diff -urN nonexistant/sh/dotcmd/out/case_return_case.out tests/bin/sh/dotcmd/out/case_return_case.out
--- nonexistant/sh/dotcmd/out/case_return_case.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/case_return_case.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+before case
+before dotcmd
+before case
+before return
+after dotcmd, return value: 0
+after case
diff -urN nonexistant/sh/dotcmd/out/case_return_compound.out tests/bin/sh/dotcmd/out/case_return_compound.out
--- nonexistant/sh/dotcmd/out/case_return_compound.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/case_return_compound.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+before case
+before dotcmd
+compound start
+before return
+after dotcmd, return value: 0
+after case
diff -urN nonexistant/sh/dotcmd/out/case_return_file.out tests/bin/sh/dotcmd/out/case_return_file.out
--- nonexistant/sh/dotcmd/out/case_return_file.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/case_return_file.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,5 @@
+before case
+before dotcmd
+before return
+after dotcmd, return value: 0
+after case
diff -urN nonexistant/sh/dotcmd/out/case_return_for.out tests/bin/sh/dotcmd/out/case_return_for.out
--- nonexistant/sh/dotcmd/out/case_return_for.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/case_return_for.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+before case
+before dotcmd
+before for
+before return
+after dotcmd, return value: 0
+after case
diff -urN nonexistant/sh/dotcmd/out/case_return_func.out tests/bin/sh/dotcmd/out/case_return_func.out
--- nonexistant/sh/dotcmd/out/case_return_func.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/case_return_func.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,7 @@
+before case
+before dotcmd
+before function
+before return
+after function
+after dotcmd, return value: 0
+after case
diff -urN nonexistant/sh/dotcmd/out/case_return_subshell.out tests/bin/sh/dotcmd/out/case_return_subshell.out
--- nonexistant/sh/dotcmd/out/case_return_subshell.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/case_return_subshell.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+before case
+before dotcmd
+subshell start
+before return
+after dotcmd, return value: 0
+after case
diff -urN nonexistant/sh/dotcmd/out/case_return_until.out tests/bin/sh/dotcmd/out/case_return_until.out
--- nonexistant/sh/dotcmd/out/case_return_until.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/case_return_until.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+before case
+before dotcmd
+before until
+before return
+after dotcmd, return value: 0
+after case
diff -urN nonexistant/sh/dotcmd/out/case_return_while.out tests/bin/sh/dotcmd/out/case_return_while.out
--- nonexistant/sh/dotcmd/out/case_return_while.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/case_return_while.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+before case
+before dotcmd
+before while
+before return
+after dotcmd, return value: 0
+after case
diff -urN nonexistant/sh/dotcmd/out/compound_break_case.out tests/bin/sh/dotcmd/out/compound_break_case.out
--- nonexistant/sh/dotcmd/out/compound_break_case.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/compound_break_case.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+compound start
+before dotcmd
+before case
+before break
+after break, return value: 0
+after case
+after dotcmd, return value: 0
+compound end
diff -urN nonexistant/sh/dotcmd/out/compound_break_compound.out tests/bin/sh/dotcmd/out/compound_break_compound.out
--- nonexistant/sh/dotcmd/out/compound_break_compound.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/compound_break_compound.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+compound start
+before dotcmd
+compound start
+before break
+after break, return value: 0
+compound end
+after dotcmd, return value: 0
+compound end
diff -urN nonexistant/sh/dotcmd/out/compound_break_file.out tests/bin/sh/dotcmd/out/compound_break_file.out
--- nonexistant/sh/dotcmd/out/compound_break_file.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/compound_break_file.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+compound start
+before dotcmd
+before break
+after break, return value: 0
+after dotcmd, return value: 0
+compound end
diff -urN nonexistant/sh/dotcmd/out/compound_break_for.out tests/bin/sh/dotcmd/out/compound_break_for.out
--- nonexistant/sh/dotcmd/out/compound_break_for.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/compound_break_for.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,7 @@
+compound start
+before dotcmd
+before for
+before break
+after for
+after dotcmd, return value: 0
+compound end
diff -urN nonexistant/sh/dotcmd/out/compound_break_func.out tests/bin/sh/dotcmd/out/compound_break_func.out
--- nonexistant/sh/dotcmd/out/compound_break_func.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/compound_break_func.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+compound start
+before dotcmd
+before function
+before break
+after break
+after function
+after dotcmd, return value: 0
+compound end
diff -urN nonexistant/sh/dotcmd/out/compound_break_subshell.out tests/bin/sh/dotcmd/out/compound_break_subshell.out
--- nonexistant/sh/dotcmd/out/compound_break_subshell.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/compound_break_subshell.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+compound start
+before dotcmd
+subshell start
+before break
+after break, return value: 0
+subshell end
+after dotcmd, return value: 0
+compound end
diff -urN nonexistant/sh/dotcmd/out/compound_break_until.out tests/bin/sh/dotcmd/out/compound_break_until.out
--- nonexistant/sh/dotcmd/out/compound_break_until.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/compound_break_until.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,7 @@
+compound start
+before dotcmd
+before until
+before break
+after until
+after dotcmd, return value: 0
+compound end
diff -urN nonexistant/sh/dotcmd/out/compound_break_while.out tests/bin/sh/dotcmd/out/compound_break_while.out
--- nonexistant/sh/dotcmd/out/compound_break_while.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/compound_break_while.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,7 @@
+compound start
+before dotcmd
+before while
+before break
+after while
+after dotcmd, return value: 0
+compound end
diff -urN nonexistant/sh/dotcmd/out/compound_continue_case.out tests/bin/sh/dotcmd/out/compound_continue_case.out
--- nonexistant/sh/dotcmd/out/compound_continue_case.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/compound_continue_case.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+compound start
+before dotcmd
+before case
+before continue
+after continue, return value: 0
+after case
+after dotcmd, return value: 0
+compound end
diff -urN nonexistant/sh/dotcmd/out/compound_continue_compound.out tests/bin/sh/dotcmd/out/compound_continue_compound.out
--- nonexistant/sh/dotcmd/out/compound_continue_compound.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/compound_continue_compound.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+compound start
+before dotcmd
+compound start
+before continue
+after continue, return value: 0
+compound end
+after dotcmd, return value: 0
+compound end
diff -urN nonexistant/sh/dotcmd/out/compound_continue_file.out tests/bin/sh/dotcmd/out/compound_continue_file.out
--- nonexistant/sh/dotcmd/out/compound_continue_file.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/compound_continue_file.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+compound start
+before dotcmd
+before continue
+after continue, return value: 0
+after dotcmd, return value: 0
+compound end
diff -urN nonexistant/sh/dotcmd/out/compound_continue_for.out tests/bin/sh/dotcmd/out/compound_continue_for.out
--- nonexistant/sh/dotcmd/out/compound_continue_for.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/compound_continue_for.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+compound start
+before dotcmd
+before for
+before continue
+before continue
+after for
+after dotcmd, return value: 0
+compound end
diff -urN nonexistant/sh/dotcmd/out/compound_continue_func.out tests/bin/sh/dotcmd/out/compound_continue_func.out
--- nonexistant/sh/dotcmd/out/compound_continue_func.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/compound_continue_func.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+compound start
+before dotcmd
+before function
+before continue
+after continue
+after function
+after dotcmd, return value: 0
+compound end
diff -urN nonexistant/sh/dotcmd/out/compound_continue_subshell.out tests/bin/sh/dotcmd/out/compound_continue_subshell.out
--- nonexistant/sh/dotcmd/out/compound_continue_subshell.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/compound_continue_subshell.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+compound start
+before dotcmd
+subshell start
+before continue
+after continue, return value: 0
+subshell end
+after dotcmd, return value: 0
+compound end
diff -urN nonexistant/sh/dotcmd/out/compound_continue_until.out tests/bin/sh/dotcmd/out/compound_continue_until.out
--- nonexistant/sh/dotcmd/out/compound_continue_until.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/compound_continue_until.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+compound start
+before dotcmd
+before until
+before continue
+before continue
+after until
+after dotcmd, return value: 0
+compound end
diff -urN nonexistant/sh/dotcmd/out/compound_continue_while.out tests/bin/sh/dotcmd/out/compound_continue_while.out
--- nonexistant/sh/dotcmd/out/compound_continue_while.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/compound_continue_while.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+compound start
+before dotcmd
+before while
+before continue
+before continue
+after while
+after dotcmd, return value: 0
+compound end
diff -urN nonexistant/sh/dotcmd/out/compound_return_case.out tests/bin/sh/dotcmd/out/compound_return_case.out
--- nonexistant/sh/dotcmd/out/compound_return_case.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/compound_return_case.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+compound start
+before dotcmd
+before case
+before return
+after dotcmd, return value: 0
+compound end
diff -urN nonexistant/sh/dotcmd/out/compound_return_compound.out tests/bin/sh/dotcmd/out/compound_return_compound.out
--- nonexistant/sh/dotcmd/out/compound_return_compound.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/compound_return_compound.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+compound start
+before dotcmd
+compound start
+before return
+after dotcmd, return value: 0
+compound end
diff -urN nonexistant/sh/dotcmd/out/compound_return_file.out tests/bin/sh/dotcmd/out/compound_return_file.out
--- nonexistant/sh/dotcmd/out/compound_return_file.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/compound_return_file.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,5 @@
+compound start
+before dotcmd
+before return
+after dotcmd, return value: 0
+compound end
diff -urN nonexistant/sh/dotcmd/out/compound_return_for.out tests/bin/sh/dotcmd/out/compound_return_for.out
--- nonexistant/sh/dotcmd/out/compound_return_for.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/compound_return_for.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+compound start
+before dotcmd
+before for
+before return
+after dotcmd, return value: 0
+compound end
diff -urN nonexistant/sh/dotcmd/out/compound_return_func.out tests/bin/sh/dotcmd/out/compound_return_func.out
--- nonexistant/sh/dotcmd/out/compound_return_func.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/compound_return_func.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,7 @@
+compound start
+before dotcmd
+before function
+before return
+after function
+after dotcmd, return value: 0
+compound end
diff -urN nonexistant/sh/dotcmd/out/compound_return_subshell.out tests/bin/sh/dotcmd/out/compound_return_subshell.out
--- nonexistant/sh/dotcmd/out/compound_return_subshell.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/compound_return_subshell.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+compound start
+before dotcmd
+subshell start
+before return
+after dotcmd, return value: 0
+compound end
diff -urN nonexistant/sh/dotcmd/out/compound_return_until.out tests/bin/sh/dotcmd/out/compound_return_until.out
--- nonexistant/sh/dotcmd/out/compound_return_until.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/compound_return_until.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+compound start
+before dotcmd
+before until
+before return
+after dotcmd, return value: 0
+compound end
diff -urN nonexistant/sh/dotcmd/out/compound_return_while.out tests/bin/sh/dotcmd/out/compound_return_while.out
--- nonexistant/sh/dotcmd/out/compound_return_while.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/compound_return_while.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+compound start
+before dotcmd
+before while
+before return
+after dotcmd, return value: 0
+compound end
diff -urN nonexistant/sh/dotcmd/out/file_break_case.out tests/bin/sh/dotcmd/out/file_break_case.out
--- nonexistant/sh/dotcmd/out/file_break_case.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/file_break_case.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+before dotcmd
+before case
+before break
+after break, return value: 0
+after case
+after dotcmd, return value: 0
diff -urN nonexistant/sh/dotcmd/out/file_break_compound.out tests/bin/sh/dotcmd/out/file_break_compound.out
--- nonexistant/sh/dotcmd/out/file_break_compound.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/file_break_compound.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+before dotcmd
+compound start
+before break
+after break, return value: 0
+compound end
+after dotcmd, return value: 0
diff -urN nonexistant/sh/dotcmd/out/file_break_file.out tests/bin/sh/dotcmd/out/file_break_file.out
--- nonexistant/sh/dotcmd/out/file_break_file.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/file_break_file.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,4 @@
+before dotcmd
+before break
+after break, return value: 0
+after dotcmd, return value: 0
diff -urN nonexistant/sh/dotcmd/out/file_break_for.out tests/bin/sh/dotcmd/out/file_break_for.out
--- nonexistant/sh/dotcmd/out/file_break_for.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/file_break_for.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,5 @@
+before dotcmd
+before for
+before break
+after for
+after dotcmd, return value: 0
diff -urN nonexistant/sh/dotcmd/out/file_break_func.out tests/bin/sh/dotcmd/out/file_break_func.out
--- nonexistant/sh/dotcmd/out/file_break_func.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/file_break_func.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+before dotcmd
+before function
+before break
+after break
+after function
+after dotcmd, return value: 0
diff -urN nonexistant/sh/dotcmd/out/file_break_subshell.out tests/bin/sh/dotcmd/out/file_break_subshell.out
--- nonexistant/sh/dotcmd/out/file_break_subshell.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/file_break_subshell.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+before dotcmd
+subshell start
+before break
+after break, return value: 0
+subshell end
+after dotcmd, return value: 0
diff -urN nonexistant/sh/dotcmd/out/file_break_until.out tests/bin/sh/dotcmd/out/file_break_until.out
--- nonexistant/sh/dotcmd/out/file_break_until.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/file_break_until.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,5 @@
+before dotcmd
+before until
+before break
+after until
+after dotcmd, return value: 0
diff -urN nonexistant/sh/dotcmd/out/file_break_while.out tests/bin/sh/dotcmd/out/file_break_while.out
--- nonexistant/sh/dotcmd/out/file_break_while.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/file_break_while.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,5 @@
+before dotcmd
+before while
+before break
+after while
+after dotcmd, return value: 0
diff -urN nonexistant/sh/dotcmd/out/file_continue_case.out tests/bin/sh/dotcmd/out/file_continue_case.out
--- nonexistant/sh/dotcmd/out/file_continue_case.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/file_continue_case.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+before dotcmd
+before case
+before continue
+after continue, return value: 0
+after case
+after dotcmd, return value: 0
diff -urN nonexistant/sh/dotcmd/out/file_continue_compound.out tests/bin/sh/dotcmd/out/file_continue_compound.out
--- nonexistant/sh/dotcmd/out/file_continue_compound.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/file_continue_compound.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+before dotcmd
+compound start
+before continue
+after continue, return value: 0
+compound end
+after dotcmd, return value: 0
diff -urN nonexistant/sh/dotcmd/out/file_continue_file.out tests/bin/sh/dotcmd/out/file_continue_file.out
--- nonexistant/sh/dotcmd/out/file_continue_file.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/file_continue_file.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,4 @@
+before dotcmd
+before continue
+after continue, return value: 0
+after dotcmd, return value: 0
diff -urN nonexistant/sh/dotcmd/out/file_continue_for.out tests/bin/sh/dotcmd/out/file_continue_for.out
--- nonexistant/sh/dotcmd/out/file_continue_for.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/file_continue_for.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+before dotcmd
+before for
+before continue
+before continue
+after for
+after dotcmd, return value: 0
diff -urN nonexistant/sh/dotcmd/out/file_continue_func.out tests/bin/sh/dotcmd/out/file_continue_func.out
--- nonexistant/sh/dotcmd/out/file_continue_func.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/file_continue_func.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+before dotcmd
+before function
+before continue
+after continue
+after function
+after dotcmd, return value: 0
diff -urN nonexistant/sh/dotcmd/out/file_continue_subshell.out tests/bin/sh/dotcmd/out/file_continue_subshell.out
--- nonexistant/sh/dotcmd/out/file_continue_subshell.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/file_continue_subshell.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+before dotcmd
+subshell start
+before continue
+after continue, return value: 0
+subshell end
+after dotcmd, return value: 0
diff -urN nonexistant/sh/dotcmd/out/file_continue_until.out tests/bin/sh/dotcmd/out/file_continue_until.out
--- nonexistant/sh/dotcmd/out/file_continue_until.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/file_continue_until.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+before dotcmd
+before until
+before continue
+before continue
+after until
+after dotcmd, return value: 0
diff -urN nonexistant/sh/dotcmd/out/file_continue_while.out tests/bin/sh/dotcmd/out/file_continue_while.out
--- nonexistant/sh/dotcmd/out/file_continue_while.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/file_continue_while.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+before dotcmd
+before while
+before continue
+before continue
+after while
+after dotcmd, return value: 0
diff -urN nonexistant/sh/dotcmd/out/file_return_case.out tests/bin/sh/dotcmd/out/file_return_case.out
--- nonexistant/sh/dotcmd/out/file_return_case.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/file_return_case.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,4 @@
+before dotcmd
+before case
+before return
+after dotcmd, return value: 0
diff -urN nonexistant/sh/dotcmd/out/file_return_compound.out tests/bin/sh/dotcmd/out/file_return_compound.out
--- nonexistant/sh/dotcmd/out/file_return_compound.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/file_return_compound.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,4 @@
+before dotcmd
+compound start
+before return
+after dotcmd, return value: 0
diff -urN nonexistant/sh/dotcmd/out/file_return_file.out tests/bin/sh/dotcmd/out/file_return_file.out
--- nonexistant/sh/dotcmd/out/file_return_file.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/file_return_file.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,3 @@
+before dotcmd
+before return
+after dotcmd, return value: 0
diff -urN nonexistant/sh/dotcmd/out/file_return_for.out tests/bin/sh/dotcmd/out/file_return_for.out
--- nonexistant/sh/dotcmd/out/file_return_for.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/file_return_for.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,4 @@
+before dotcmd
+before for
+before return
+after dotcmd, return value: 0
diff -urN nonexistant/sh/dotcmd/out/file_return_func.out tests/bin/sh/dotcmd/out/file_return_func.out
--- nonexistant/sh/dotcmd/out/file_return_func.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/file_return_func.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,5 @@
+before dotcmd
+before function
+before return
+after function
+after dotcmd, return value: 0
diff -urN nonexistant/sh/dotcmd/out/file_return_subshell.out tests/bin/sh/dotcmd/out/file_return_subshell.out
--- nonexistant/sh/dotcmd/out/file_return_subshell.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/file_return_subshell.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,4 @@
+before dotcmd
+subshell start
+before return
+after dotcmd, return value: 0
diff -urN nonexistant/sh/dotcmd/out/file_return_until.out tests/bin/sh/dotcmd/out/file_return_until.out
--- nonexistant/sh/dotcmd/out/file_return_until.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/file_return_until.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,4 @@
+before dotcmd
+before until
+before return
+after dotcmd, return value: 0
diff -urN nonexistant/sh/dotcmd/out/file_return_while.out tests/bin/sh/dotcmd/out/file_return_while.out
--- nonexistant/sh/dotcmd/out/file_return_while.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/file_return_while.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,4 @@
+before dotcmd
+before while
+before return
+after dotcmd, return value: 0
diff -urN nonexistant/sh/dotcmd/out/for_break_case.out tests/bin/sh/dotcmd/out/for_break_case.out
--- nonexistant/sh/dotcmd/out/for_break_case.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/for_break_case.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,5 @@
+before for
+before dotcmd
+before case
+before break
+after for
diff -urN nonexistant/sh/dotcmd/out/for_break_compound.out tests/bin/sh/dotcmd/out/for_break_compound.out
--- nonexistant/sh/dotcmd/out/for_break_compound.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/for_break_compound.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,5 @@
+before for
+before dotcmd
+compound start
+before break
+after for
diff -urN nonexistant/sh/dotcmd/out/for_break_file.out tests/bin/sh/dotcmd/out/for_break_file.out
--- nonexistant/sh/dotcmd/out/for_break_file.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/for_break_file.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,4 @@
+before for
+before dotcmd
+before break
+after for
diff -urN nonexistant/sh/dotcmd/out/for_break_for.out tests/bin/sh/dotcmd/out/for_break_for.out
--- nonexistant/sh/dotcmd/out/for_break_for.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/for_break_for.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,12 @@
+before for
+before dotcmd
+before for
+before break
+after for
+after dotcmd, return value: 0
+before dotcmd
+before for
+before break
+after for
+after dotcmd, return value: 0
+after for
diff -urN nonexistant/sh/dotcmd/out/for_break_func.out tests/bin/sh/dotcmd/out/for_break_func.out
--- nonexistant/sh/dotcmd/out/for_break_func.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/for_break_func.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,5 @@
+before for
+before dotcmd
+before function
+before break
+after for
diff -urN nonexistant/sh/dotcmd/out/for_break_subshell.out tests/bin/sh/dotcmd/out/for_break_subshell.out
--- nonexistant/sh/dotcmd/out/for_break_subshell.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/for_break_subshell.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,10 @@
+before for
+before dotcmd
+subshell start
+before break
+after dotcmd, return value: 0
+before dotcmd
+subshell start
+before break
+after dotcmd, return value: 0
+after for
diff -urN nonexistant/sh/dotcmd/out/for_break_until.out tests/bin/sh/dotcmd/out/for_break_until.out
--- nonexistant/sh/dotcmd/out/for_break_until.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/for_break_until.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,12 @@
+before for
+before dotcmd
+before until
+before break
+after until
+after dotcmd, return value: 0
+before dotcmd
+before until
+before break
+after until
+after dotcmd, return value: 0
+after for
diff -urN nonexistant/sh/dotcmd/out/for_break_while.out tests/bin/sh/dotcmd/out/for_break_while.out
--- nonexistant/sh/dotcmd/out/for_break_while.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/for_break_while.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,12 @@
+before for
+before dotcmd
+before while
+before break
+after while
+after dotcmd, return value: 0
+before dotcmd
+before while
+before break
+after while
+after dotcmd, return value: 0
+after for
diff -urN nonexistant/sh/dotcmd/out/for_continue_case.out tests/bin/sh/dotcmd/out/for_continue_case.out
--- nonexistant/sh/dotcmd/out/for_continue_case.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/for_continue_case.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+before for
+before dotcmd
+before case
+before continue
+before dotcmd
+before case
+before continue
+after for
diff -urN nonexistant/sh/dotcmd/out/for_continue_compound.out tests/bin/sh/dotcmd/out/for_continue_compound.out
--- nonexistant/sh/dotcmd/out/for_continue_compound.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/for_continue_compound.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+before for
+before dotcmd
+compound start
+before continue
+before dotcmd
+compound start
+before continue
+after for
diff -urN nonexistant/sh/dotcmd/out/for_continue_file.out tests/bin/sh/dotcmd/out/for_continue_file.out
--- nonexistant/sh/dotcmd/out/for_continue_file.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/for_continue_file.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+before for
+before dotcmd
+before continue
+before dotcmd
+before continue
+after for
diff -urN nonexistant/sh/dotcmd/out/for_continue_for.out tests/bin/sh/dotcmd/out/for_continue_for.out
--- nonexistant/sh/dotcmd/out/for_continue_for.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/for_continue_for.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,14 @@
+before for
+before dotcmd
+before for
+before continue
+before continue
+after for
+after dotcmd, return value: 0
+before dotcmd
+before for
+before continue
+before continue
+after for
+after dotcmd, return value: 0
+after for
diff -urN nonexistant/sh/dotcmd/out/for_continue_func.out tests/bin/sh/dotcmd/out/for_continue_func.out
--- nonexistant/sh/dotcmd/out/for_continue_func.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/for_continue_func.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+before for
+before dotcmd
+before function
+before continue
+before dotcmd
+before function
+before continue
+after for
diff -urN nonexistant/sh/dotcmd/out/for_continue_subshell.out tests/bin/sh/dotcmd/out/for_continue_subshell.out
--- nonexistant/sh/dotcmd/out/for_continue_subshell.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/for_continue_subshell.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,10 @@
+before for
+before dotcmd
+subshell start
+before continue
+after dotcmd, return value: 0
+before dotcmd
+subshell start
+before continue
+after dotcmd, return value: 0
+after for
diff -urN nonexistant/sh/dotcmd/out/for_continue_until.out tests/bin/sh/dotcmd/out/for_continue_until.out
--- nonexistant/sh/dotcmd/out/for_continue_until.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/for_continue_until.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,14 @@
+before for
+before dotcmd
+before until
+before continue
+before continue
+after until
+after dotcmd, return value: 0
+before dotcmd
+before until
+before continue
+before continue
+after until
+after dotcmd, return value: 0
+after for
diff -urN nonexistant/sh/dotcmd/out/for_continue_while.out tests/bin/sh/dotcmd/out/for_continue_while.out
--- nonexistant/sh/dotcmd/out/for_continue_while.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/for_continue_while.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,14 @@
+before for
+before dotcmd
+before while
+before continue
+before continue
+after while
+after dotcmd, return value: 0
+before dotcmd
+before while
+before continue
+before continue
+after while
+after dotcmd, return value: 0
+after for
diff -urN nonexistant/sh/dotcmd/out/for_return_case.out tests/bin/sh/dotcmd/out/for_return_case.out
--- nonexistant/sh/dotcmd/out/for_return_case.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/for_return_case.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,10 @@
+before for
+before dotcmd
+before case
+before return
+after dotcmd, return value: 0
+before dotcmd
+before case
+before return
+after dotcmd, return value: 0
+after for
diff -urN nonexistant/sh/dotcmd/out/for_return_compound.out tests/bin/sh/dotcmd/out/for_return_compound.out
--- nonexistant/sh/dotcmd/out/for_return_compound.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/for_return_compound.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,10 @@
+before for
+before dotcmd
+compound start
+before return
+after dotcmd, return value: 0
+before dotcmd
+compound start
+before return
+after dotcmd, return value: 0
+after for
diff -urN nonexistant/sh/dotcmd/out/for_return_file.out tests/bin/sh/dotcmd/out/for_return_file.out
--- nonexistant/sh/dotcmd/out/for_return_file.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/for_return_file.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+before for
+before dotcmd
+before return
+after dotcmd, return value: 0
+before dotcmd
+before return
+after dotcmd, return value: 0
+after for
diff -urN nonexistant/sh/dotcmd/out/for_return_for.out tests/bin/sh/dotcmd/out/for_return_for.out
--- nonexistant/sh/dotcmd/out/for_return_for.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/for_return_for.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,10 @@
+before for
+before dotcmd
+before for
+before return
+after dotcmd, return value: 0
+before dotcmd
+before for
+before return
+after dotcmd, return value: 0
+after for
diff -urN nonexistant/sh/dotcmd/out/for_return_func.out tests/bin/sh/dotcmd/out/for_return_func.out
--- nonexistant/sh/dotcmd/out/for_return_func.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/for_return_func.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,12 @@
+before for
+before dotcmd
+before function
+before return
+after function
+after dotcmd, return value: 0
+before dotcmd
+before function
+before return
+after function
+after dotcmd, return value: 0
+after for
diff -urN nonexistant/sh/dotcmd/out/for_return_subshell.out tests/bin/sh/dotcmd/out/for_return_subshell.out
--- nonexistant/sh/dotcmd/out/for_return_subshell.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/for_return_subshell.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,10 @@
+before for
+before dotcmd
+subshell start
+before return
+after dotcmd, return value: 0
+before dotcmd
+subshell start
+before return
+after dotcmd, return value: 0
+after for
diff -urN nonexistant/sh/dotcmd/out/for_return_until.out tests/bin/sh/dotcmd/out/for_return_until.out
--- nonexistant/sh/dotcmd/out/for_return_until.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/for_return_until.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,10 @@
+before for
+before dotcmd
+before until
+before return
+after dotcmd, return value: 0
+before dotcmd
+before until
+before return
+after dotcmd, return value: 0
+after for
diff -urN nonexistant/sh/dotcmd/out/for_return_while.out tests/bin/sh/dotcmd/out/for_return_while.out
--- nonexistant/sh/dotcmd/out/for_return_while.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/for_return_while.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,10 @@
+before for
+before dotcmd
+before while
+before return
+after dotcmd, return value: 0
+before dotcmd
+before while
+before return
+after dotcmd, return value: 0
+after for
diff -urN nonexistant/sh/dotcmd/out/func_break_case.out tests/bin/sh/dotcmd/out/func_break_case.out
--- nonexistant/sh/dotcmd/out/func_break_case.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/func_break_case.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+before function
+before dotcmd
+before case
+before break
+after break, return value: 0
+after case
+after dotcmd
+after function
diff -urN nonexistant/sh/dotcmd/out/func_break_compound.out tests/bin/sh/dotcmd/out/func_break_compound.out
--- nonexistant/sh/dotcmd/out/func_break_compound.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/func_break_compound.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,8 @@
+before function
+before dotcmd
+compound start
+before break
+after break, return value: 0
+compound end
+after dotcmd
+after function
diff -urN nonexistant/sh/dotcmd/out/func_break_file.out tests/bin/sh/dotcmd/out/func_break_file.out
--- nonexistant/sh/dotcmd/out/func_break_file.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/func_break_file.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,6 @@
+before function
+before dotcmd
+before break
+after break, return value: 0
+after dotcmd
+after function
diff -urN nonexistant/sh/dotcmd/out/func_break_for.out tests/bin/sh/dotcmd/out/func_break_for.out
--- nonexistant/sh/dotcmd/out/func_break_for.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/func_break_for.out 2014-05-28 16:45:07.000000000 +0300
@@ -0,0 +1,7 @@
+before function
+before dotcmd
+before for
+before break
+after for
+after dotcmd
+after function
diff -urN nonexistant/sh/dotcmd/out/func_break_func.out tests/bin/sh/dotcmd/out/func_break_func.out
--- nonexistant/sh/dotcmd/out/func_break_func.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/func_break_func.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+before function
+before dotcmd
+before function
+before break
+after break
+after function
+after dotcmd
+after function
diff -urN nonexistant/sh/dotcmd/out/func_break_subshell.out tests/bin/sh/dotcmd/out/func_break_subshell.out
--- nonexistant/sh/dotcmd/out/func_break_subshell.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/func_break_subshell.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+before function
+before dotcmd
+subshell start
+before break
+after break, return value: 0
+subshell end
+after dotcmd
+after function
diff -urN nonexistant/sh/dotcmd/out/func_break_until.out tests/bin/sh/dotcmd/out/func_break_until.out
--- nonexistant/sh/dotcmd/out/func_break_until.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/func_break_until.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,7 @@
+before function
+before dotcmd
+before until
+before break
+after until
+after dotcmd
+after function
diff -urN nonexistant/sh/dotcmd/out/func_break_while.out tests/bin/sh/dotcmd/out/func_break_while.out
--- nonexistant/sh/dotcmd/out/func_break_while.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/func_break_while.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,7 @@
+before function
+before dotcmd
+before while
+before break
+after while
+after dotcmd
+after function
diff -urN nonexistant/sh/dotcmd/out/func_continue_case.out tests/bin/sh/dotcmd/out/func_continue_case.out
--- nonexistant/sh/dotcmd/out/func_continue_case.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/func_continue_case.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+before function
+before dotcmd
+before case
+before continue
+after continue, return value: 0
+after case
+after dotcmd
+after function
diff -urN nonexistant/sh/dotcmd/out/func_continue_compound.out tests/bin/sh/dotcmd/out/func_continue_compound.out
--- nonexistant/sh/dotcmd/out/func_continue_compound.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/func_continue_compound.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+before function
+before dotcmd
+compound start
+before continue
+after continue, return value: 0
+compound end
+after dotcmd
+after function
diff -urN nonexistant/sh/dotcmd/out/func_continue_file.out tests/bin/sh/dotcmd/out/func_continue_file.out
--- nonexistant/sh/dotcmd/out/func_continue_file.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/func_continue_file.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,6 @@
+before function
+before dotcmd
+before continue
+after continue, return value: 0
+after dotcmd
+after function
diff -urN nonexistant/sh/dotcmd/out/func_continue_for.out tests/bin/sh/dotcmd/out/func_continue_for.out
--- nonexistant/sh/dotcmd/out/func_continue_for.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/func_continue_for.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+before function
+before dotcmd
+before for
+before continue
+before continue
+after for
+after dotcmd
+after function
diff -urN nonexistant/sh/dotcmd/out/func_continue_func.out tests/bin/sh/dotcmd/out/func_continue_func.out
--- nonexistant/sh/dotcmd/out/func_continue_func.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/func_continue_func.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+before function
+before dotcmd
+before function
+before continue
+after continue
+after function
+after dotcmd
+after function
diff -urN nonexistant/sh/dotcmd/out/func_continue_subshell.out tests/bin/sh/dotcmd/out/func_continue_subshell.out
--- nonexistant/sh/dotcmd/out/func_continue_subshell.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/func_continue_subshell.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+before function
+before dotcmd
+subshell start
+before continue
+after continue, return value: 0
+subshell end
+after dotcmd
+after function
diff -urN nonexistant/sh/dotcmd/out/func_continue_until.out tests/bin/sh/dotcmd/out/func_continue_until.out
--- nonexistant/sh/dotcmd/out/func_continue_until.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/func_continue_until.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+before function
+before dotcmd
+before until
+before continue
+before continue
+after until
+after dotcmd
+after function
diff -urN nonexistant/sh/dotcmd/out/func_continue_while.out tests/bin/sh/dotcmd/out/func_continue_while.out
--- nonexistant/sh/dotcmd/out/func_continue_while.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/func_continue_while.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+before function
+before dotcmd
+before while
+before continue
+before continue
+after while
+after dotcmd
+after function
diff -urN nonexistant/sh/dotcmd/out/func_return_case.out tests/bin/sh/dotcmd/out/func_return_case.out
--- nonexistant/sh/dotcmd/out/func_return_case.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/func_return_case.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,6 @@
+before function
+before dotcmd
+before case
+before return
+after dotcmd
+after function
diff -urN nonexistant/sh/dotcmd/out/func_return_compound.out tests/bin/sh/dotcmd/out/func_return_compound.out
--- nonexistant/sh/dotcmd/out/func_return_compound.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/func_return_compound.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,6 @@
+before function
+before dotcmd
+compound start
+before return
+after dotcmd
+after function
diff -urN nonexistant/sh/dotcmd/out/func_return_file.out tests/bin/sh/dotcmd/out/func_return_file.out
--- nonexistant/sh/dotcmd/out/func_return_file.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/func_return_file.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,5 @@
+before function
+before dotcmd
+before return
+after dotcmd
+after function
diff -urN nonexistant/sh/dotcmd/out/func_return_for.out tests/bin/sh/dotcmd/out/func_return_for.out
--- nonexistant/sh/dotcmd/out/func_return_for.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/func_return_for.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,6 @@
+before function
+before dotcmd
+before for
+before return
+after dotcmd
+after function
diff -urN nonexistant/sh/dotcmd/out/func_return_func.out tests/bin/sh/dotcmd/out/func_return_func.out
--- nonexistant/sh/dotcmd/out/func_return_func.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/func_return_func.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,7 @@
+before function
+before dotcmd
+before function
+before return
+after function
+after dotcmd
+after function
diff -urN nonexistant/sh/dotcmd/out/func_return_subshell.out tests/bin/sh/dotcmd/out/func_return_subshell.out
--- nonexistant/sh/dotcmd/out/func_return_subshell.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/func_return_subshell.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,6 @@
+before function
+before dotcmd
+subshell start
+before return
+after dotcmd
+after function
diff -urN nonexistant/sh/dotcmd/out/func_return_until.out tests/bin/sh/dotcmd/out/func_return_until.out
--- nonexistant/sh/dotcmd/out/func_return_until.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/func_return_until.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,6 @@
+before function
+before dotcmd
+before until
+before return
+after dotcmd
+after function
diff -urN nonexistant/sh/dotcmd/out/func_return_while.out tests/bin/sh/dotcmd/out/func_return_while.out
--- nonexistant/sh/dotcmd/out/func_return_while.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/func_return_while.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,6 @@
+before function
+before dotcmd
+before while
+before return
+after dotcmd
+after function
diff -urN nonexistant/sh/dotcmd/out/subshell_break_case.out tests/bin/sh/dotcmd/out/subshell_break_case.out
--- nonexistant/sh/dotcmd/out/subshell_break_case.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/subshell_break_case.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+subshell start
+before dotcmd
+before case
+before break
+after break, return value: 0
+after case
+after dotcmd, return value: 0
+subshell end
diff -urN nonexistant/sh/dotcmd/out/subshell_break_compound.out tests/bin/sh/dotcmd/out/subshell_break_compound.out
--- nonexistant/sh/dotcmd/out/subshell_break_compound.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/subshell_break_compound.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+subshell start
+before dotcmd
+compound start
+before break
+after break, return value: 0
+compound end
+after dotcmd, return value: 0
+subshell end
diff -urN nonexistant/sh/dotcmd/out/subshell_break_file.out tests/bin/sh/dotcmd/out/subshell_break_file.out
--- nonexistant/sh/dotcmd/out/subshell_break_file.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/subshell_break_file.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,6 @@
+subshell start
+before dotcmd
+before break
+after break, return value: 0
+after dotcmd, return value: 0
+subshell end
diff -urN nonexistant/sh/dotcmd/out/subshell_break_for.out tests/bin/sh/dotcmd/out/subshell_break_for.out
--- nonexistant/sh/dotcmd/out/subshell_break_for.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/subshell_break_for.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,7 @@
+subshell start
+before dotcmd
+before for
+before break
+after for
+after dotcmd, return value: 0
+subshell end
diff -urN nonexistant/sh/dotcmd/out/subshell_break_func.out tests/bin/sh/dotcmd/out/subshell_break_func.out
--- nonexistant/sh/dotcmd/out/subshell_break_func.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/subshell_break_func.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+subshell start
+before dotcmd
+before function
+before break
+after break
+after function
+after dotcmd, return value: 0
+subshell end
diff -urN nonexistant/sh/dotcmd/out/subshell_break_subshell.out tests/bin/sh/dotcmd/out/subshell_break_subshell.out
--- nonexistant/sh/dotcmd/out/subshell_break_subshell.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/subshell_break_subshell.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+subshell start
+before dotcmd
+subshell start
+before break
+after break, return value: 0
+subshell end
+after dotcmd, return value: 0
+subshell end
diff -urN nonexistant/sh/dotcmd/out/subshell_break_until.out tests/bin/sh/dotcmd/out/subshell_break_until.out
--- nonexistant/sh/dotcmd/out/subshell_break_until.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/subshell_break_until.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,7 @@
+subshell start
+before dotcmd
+before until
+before break
+after until
+after dotcmd, return value: 0
+subshell end
diff -urN nonexistant/sh/dotcmd/out/subshell_break_while.out tests/bin/sh/dotcmd/out/subshell_break_while.out
--- nonexistant/sh/dotcmd/out/subshell_break_while.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/subshell_break_while.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,7 @@
+subshell start
+before dotcmd
+before while
+before break
+after while
+after dotcmd, return value: 0
+subshell end
diff -urN nonexistant/sh/dotcmd/out/subshell_continue_case.out tests/bin/sh/dotcmd/out/subshell_continue_case.out
--- nonexistant/sh/dotcmd/out/subshell_continue_case.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/subshell_continue_case.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+subshell start
+before dotcmd
+before case
+before continue
+after continue, return value: 0
+after case
+after dotcmd, return value: 0
+subshell end
diff -urN nonexistant/sh/dotcmd/out/subshell_continue_compound.out tests/bin/sh/dotcmd/out/subshell_continue_compound.out
--- nonexistant/sh/dotcmd/out/subshell_continue_compound.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/subshell_continue_compound.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+subshell start
+before dotcmd
+compound start
+before continue
+after continue, return value: 0
+compound end
+after dotcmd, return value: 0
+subshell end
diff -urN nonexistant/sh/dotcmd/out/subshell_continue_file.out tests/bin/sh/dotcmd/out/subshell_continue_file.out
--- nonexistant/sh/dotcmd/out/subshell_continue_file.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/subshell_continue_file.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,6 @@
+subshell start
+before dotcmd
+before continue
+after continue, return value: 0
+after dotcmd, return value: 0
+subshell end
diff -urN nonexistant/sh/dotcmd/out/subshell_continue_for.out tests/bin/sh/dotcmd/out/subshell_continue_for.out
--- nonexistant/sh/dotcmd/out/subshell_continue_for.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/subshell_continue_for.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+subshell start
+before dotcmd
+before for
+before continue
+before continue
+after for
+after dotcmd, return value: 0
+subshell end
diff -urN nonexistant/sh/dotcmd/out/subshell_continue_func.out tests/bin/sh/dotcmd/out/subshell_continue_func.out
--- nonexistant/sh/dotcmd/out/subshell_continue_func.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/subshell_continue_func.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+subshell start
+before dotcmd
+before function
+before continue
+after continue
+after function
+after dotcmd, return value: 0
+subshell end
diff -urN nonexistant/sh/dotcmd/out/subshell_continue_subshell.out tests/bin/sh/dotcmd/out/subshell_continue_subshell.out
--- nonexistant/sh/dotcmd/out/subshell_continue_subshell.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/subshell_continue_subshell.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+subshell start
+before dotcmd
+subshell start
+before continue
+after continue, return value: 0
+subshell end
+after dotcmd, return value: 0
+subshell end
diff -urN nonexistant/sh/dotcmd/out/subshell_continue_until.out tests/bin/sh/dotcmd/out/subshell_continue_until.out
--- nonexistant/sh/dotcmd/out/subshell_continue_until.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/subshell_continue_until.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+subshell start
+before dotcmd
+before until
+before continue
+before continue
+after until
+after dotcmd, return value: 0
+subshell end
diff -urN nonexistant/sh/dotcmd/out/subshell_continue_while.out tests/bin/sh/dotcmd/out/subshell_continue_while.out
--- nonexistant/sh/dotcmd/out/subshell_continue_while.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/subshell_continue_while.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+subshell start
+before dotcmd
+before while
+before continue
+before continue
+after while
+after dotcmd, return value: 0
+subshell end
diff -urN nonexistant/sh/dotcmd/out/subshell_return_case.out tests/bin/sh/dotcmd/out/subshell_return_case.out
--- nonexistant/sh/dotcmd/out/subshell_return_case.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/subshell_return_case.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,6 @@
+subshell start
+before dotcmd
+before case
+before return
+after dotcmd, return value: 0
+subshell end
diff -urN nonexistant/sh/dotcmd/out/subshell_return_compound.out tests/bin/sh/dotcmd/out/subshell_return_compound.out
--- nonexistant/sh/dotcmd/out/subshell_return_compound.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/subshell_return_compound.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,6 @@
+subshell start
+before dotcmd
+compound start
+before return
+after dotcmd, return value: 0
+subshell end
diff -urN nonexistant/sh/dotcmd/out/subshell_return_file.out tests/bin/sh/dotcmd/out/subshell_return_file.out
--- nonexistant/sh/dotcmd/out/subshell_return_file.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/subshell_return_file.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,5 @@
+subshell start
+before dotcmd
+before return
+after dotcmd, return value: 0
+subshell end
diff -urN nonexistant/sh/dotcmd/out/subshell_return_for.out tests/bin/sh/dotcmd/out/subshell_return_for.out
--- nonexistant/sh/dotcmd/out/subshell_return_for.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/subshell_return_for.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,6 @@
+subshell start
+before dotcmd
+before for
+before return
+after dotcmd, return value: 0
+subshell end
diff -urN nonexistant/sh/dotcmd/out/subshell_return_func.out tests/bin/sh/dotcmd/out/subshell_return_func.out
--- nonexistant/sh/dotcmd/out/subshell_return_func.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/subshell_return_func.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,7 @@
+subshell start
+before dotcmd
+before function
+before return
+after function
+after dotcmd, return value: 0
+subshell end
diff -urN nonexistant/sh/dotcmd/out/subshell_return_subshell.out tests/bin/sh/dotcmd/out/subshell_return_subshell.out
--- nonexistant/sh/dotcmd/out/subshell_return_subshell.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/subshell_return_subshell.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,6 @@
+subshell start
+before dotcmd
+subshell start
+before return
+after dotcmd, return value: 0
+subshell end
diff -urN nonexistant/sh/dotcmd/out/subshell_return_until.out tests/bin/sh/dotcmd/out/subshell_return_until.out
--- nonexistant/sh/dotcmd/out/subshell_return_until.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/subshell_return_until.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,6 @@
+subshell start
+before dotcmd
+before until
+before return
+after dotcmd, return value: 0
+subshell end
diff -urN nonexistant/sh/dotcmd/out/subshell_return_while.out tests/bin/sh/dotcmd/out/subshell_return_while.out
--- nonexistant/sh/dotcmd/out/subshell_return_while.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/subshell_return_while.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,6 @@
+subshell start
+before dotcmd
+before while
+before return
+after dotcmd, return value: 0
+subshell end
diff -urN nonexistant/sh/dotcmd/out/until_break_case.out tests/bin/sh/dotcmd/out/until_break_case.out
--- nonexistant/sh/dotcmd/out/until_break_case.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/until_break_case.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,5 @@
+before until
+before dotcmd
+before case
+before break
+after until
diff -urN nonexistant/sh/dotcmd/out/until_break_compound.out tests/bin/sh/dotcmd/out/until_break_compound.out
--- nonexistant/sh/dotcmd/out/until_break_compound.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/until_break_compound.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,5 @@
+before until
+before dotcmd
+compound start
+before break
+after until
diff -urN nonexistant/sh/dotcmd/out/until_break_file.out tests/bin/sh/dotcmd/out/until_break_file.out
--- nonexistant/sh/dotcmd/out/until_break_file.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/until_break_file.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,4 @@
+before until
+before dotcmd
+before break
+after until
diff -urN nonexistant/sh/dotcmd/out/until_break_for.out tests/bin/sh/dotcmd/out/until_break_for.out
--- nonexistant/sh/dotcmd/out/until_break_for.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/until_break_for.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,12 @@
+before until
+before dotcmd
+before for
+before break
+after for
+after dotcmd, return value: 0
+before dotcmd
+before for
+before break
+after for
+after dotcmd, return value: 0
+after until
diff -urN nonexistant/sh/dotcmd/out/until_break_func.out tests/bin/sh/dotcmd/out/until_break_func.out
--- nonexistant/sh/dotcmd/out/until_break_func.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/until_break_func.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,5 @@
+before until
+before dotcmd
+before function
+before break
+after until
diff -urN nonexistant/sh/dotcmd/out/until_break_subshell.out tests/bin/sh/dotcmd/out/until_break_subshell.out
--- nonexistant/sh/dotcmd/out/until_break_subshell.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/until_break_subshell.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,10 @@
+before until
+before dotcmd
+subshell start
+before break
+after dotcmd, return value: 0
+before dotcmd
+subshell start
+before break
+after dotcmd, return value: 0
+after until
diff -urN nonexistant/sh/dotcmd/out/until_break_until.out tests/bin/sh/dotcmd/out/until_break_until.out
--- nonexistant/sh/dotcmd/out/until_break_until.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/until_break_until.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,12 @@
+before until
+before dotcmd
+before until
+before break
+after until
+after dotcmd, return value: 0
+before dotcmd
+before until
+before break
+after until
+after dotcmd, return value: 0
+after until
diff -urN nonexistant/sh/dotcmd/out/until_break_while.out tests/bin/sh/dotcmd/out/until_break_while.out
--- nonexistant/sh/dotcmd/out/until_break_while.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/until_break_while.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,12 @@
+before until
+before dotcmd
+before while
+before break
+after while
+after dotcmd, return value: 0
+before dotcmd
+before while
+before break
+after while
+after dotcmd, return value: 0
+after until
diff -urN nonexistant/sh/dotcmd/out/until_continue_case.out tests/bin/sh/dotcmd/out/until_continue_case.out
--- nonexistant/sh/dotcmd/out/until_continue_case.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/until_continue_case.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+before until
+before dotcmd
+before case
+before continue
+before dotcmd
+before case
+before continue
+after until
diff -urN nonexistant/sh/dotcmd/out/until_continue_compound.out tests/bin/sh/dotcmd/out/until_continue_compound.out
--- nonexistant/sh/dotcmd/out/until_continue_compound.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/until_continue_compound.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+before until
+before dotcmd
+compound start
+before continue
+before dotcmd
+compound start
+before continue
+after until
diff -urN nonexistant/sh/dotcmd/out/until_continue_file.out tests/bin/sh/dotcmd/out/until_continue_file.out
--- nonexistant/sh/dotcmd/out/until_continue_file.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/until_continue_file.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,6 @@
+before until
+before dotcmd
+before continue
+before dotcmd
+before continue
+after until
diff -urN nonexistant/sh/dotcmd/out/until_continue_for.out tests/bin/sh/dotcmd/out/until_continue_for.out
--- nonexistant/sh/dotcmd/out/until_continue_for.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/until_continue_for.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,14 @@
+before until
+before dotcmd
+before for
+before continue
+before continue
+after for
+after dotcmd, return value: 0
+before dotcmd
+before for
+before continue
+before continue
+after for
+after dotcmd, return value: 0
+after until
diff -urN nonexistant/sh/dotcmd/out/until_continue_func.out tests/bin/sh/dotcmd/out/until_continue_func.out
--- nonexistant/sh/dotcmd/out/until_continue_func.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/until_continue_func.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+before until
+before dotcmd
+before function
+before continue
+before dotcmd
+before function
+before continue
+after until
diff -urN nonexistant/sh/dotcmd/out/until_continue_subshell.out tests/bin/sh/dotcmd/out/until_continue_subshell.out
--- nonexistant/sh/dotcmd/out/until_continue_subshell.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/until_continue_subshell.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,10 @@
+before until
+before dotcmd
+subshell start
+before continue
+after dotcmd, return value: 0
+before dotcmd
+subshell start
+before continue
+after dotcmd, return value: 0
+after until
diff -urN nonexistant/sh/dotcmd/out/until_continue_until.out tests/bin/sh/dotcmd/out/until_continue_until.out
--- nonexistant/sh/dotcmd/out/until_continue_until.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/until_continue_until.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,14 @@
+before until
+before dotcmd
+before until
+before continue
+before continue
+after until
+after dotcmd, return value: 0
+before dotcmd
+before until
+before continue
+before continue
+after until
+after dotcmd, return value: 0
+after until
diff -urN nonexistant/sh/dotcmd/out/until_continue_while.out tests/bin/sh/dotcmd/out/until_continue_while.out
--- nonexistant/sh/dotcmd/out/until_continue_while.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/until_continue_while.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,14 @@
+before until
+before dotcmd
+before while
+before continue
+before continue
+after while
+after dotcmd, return value: 0
+before dotcmd
+before while
+before continue
+before continue
+after while
+after dotcmd, return value: 0
+after until
diff -urN nonexistant/sh/dotcmd/out/until_return_case.out tests/bin/sh/dotcmd/out/until_return_case.out
--- nonexistant/sh/dotcmd/out/until_return_case.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/until_return_case.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,10 @@
+before until
+before dotcmd
+before case
+before return
+after dotcmd, return value: 0
+before dotcmd
+before case
+before return
+after dotcmd, return value: 0
+after until
diff -urN nonexistant/sh/dotcmd/out/until_return_compound.out tests/bin/sh/dotcmd/out/until_return_compound.out
--- nonexistant/sh/dotcmd/out/until_return_compound.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/until_return_compound.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,10 @@
+before until
+before dotcmd
+compound start
+before return
+after dotcmd, return value: 0
+before dotcmd
+compound start
+before return
+after dotcmd, return value: 0
+after until
diff -urN nonexistant/sh/dotcmd/out/until_return_file.out tests/bin/sh/dotcmd/out/until_return_file.out
--- nonexistant/sh/dotcmd/out/until_return_file.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/until_return_file.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+before until
+before dotcmd
+before return
+after dotcmd, return value: 0
+before dotcmd
+before return
+after dotcmd, return value: 0
+after until
diff -urN nonexistant/sh/dotcmd/out/until_return_for.out tests/bin/sh/dotcmd/out/until_return_for.out
--- nonexistant/sh/dotcmd/out/until_return_for.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/until_return_for.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,10 @@
+before until
+before dotcmd
+before for
+before return
+after dotcmd, return value: 0
+before dotcmd
+before for
+before return
+after dotcmd, return value: 0
+after until
diff -urN nonexistant/sh/dotcmd/out/until_return_func.out tests/bin/sh/dotcmd/out/until_return_func.out
--- nonexistant/sh/dotcmd/out/until_return_func.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/until_return_func.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,12 @@
+before until
+before dotcmd
+before function
+before return
+after function
+after dotcmd, return value: 0
+before dotcmd
+before function
+before return
+after function
+after dotcmd, return value: 0
+after until
diff -urN nonexistant/sh/dotcmd/out/until_return_subshell.out tests/bin/sh/dotcmd/out/until_return_subshell.out
--- nonexistant/sh/dotcmd/out/until_return_subshell.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/until_return_subshell.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,10 @@
+before until
+before dotcmd
+subshell start
+before return
+after dotcmd, return value: 0
+before dotcmd
+subshell start
+before return
+after dotcmd, return value: 0
+after until
diff -urN nonexistant/sh/dotcmd/out/until_return_until.out tests/bin/sh/dotcmd/out/until_return_until.out
--- nonexistant/sh/dotcmd/out/until_return_until.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/until_return_until.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,10 @@
+before until
+before dotcmd
+before until
+before return
+after dotcmd, return value: 0
+before dotcmd
+before until
+before return
+after dotcmd, return value: 0
+after until
diff -urN nonexistant/sh/dotcmd/out/until_return_while.out tests/bin/sh/dotcmd/out/until_return_while.out
--- nonexistant/sh/dotcmd/out/until_return_while.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/until_return_while.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,10 @@
+before until
+before dotcmd
+before while
+before return
+after dotcmd, return value: 0
+before dotcmd
+before while
+before return
+after dotcmd, return value: 0
+after until
diff -urN nonexistant/sh/dotcmd/out/while_break_case.out tests/bin/sh/dotcmd/out/while_break_case.out
--- nonexistant/sh/dotcmd/out/while_break_case.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/while_break_case.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,5 @@
+before while
+before dotcmd
+before case
+before break
+after while
diff -urN nonexistant/sh/dotcmd/out/while_break_compound.out tests/bin/sh/dotcmd/out/while_break_compound.out
--- nonexistant/sh/dotcmd/out/while_break_compound.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/while_break_compound.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,5 @@
+before while
+before dotcmd
+compound start
+before break
+after while
diff -urN nonexistant/sh/dotcmd/out/while_break_file.out tests/bin/sh/dotcmd/out/while_break_file.out
--- nonexistant/sh/dotcmd/out/while_break_file.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/while_break_file.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,4 @@
+before while
+before dotcmd
+before break
+after while
diff -urN nonexistant/sh/dotcmd/out/while_break_for.out tests/bin/sh/dotcmd/out/while_break_for.out
--- nonexistant/sh/dotcmd/out/while_break_for.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/while_break_for.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,12 @@
+before while
+before dotcmd
+before for
+before break
+after for
+after dotcmd, return value: 0
+before dotcmd
+before for
+before break
+after for
+after dotcmd, return value: 0
+after while
diff -urN nonexistant/sh/dotcmd/out/while_break_func.out tests/bin/sh/dotcmd/out/while_break_func.out
--- nonexistant/sh/dotcmd/out/while_break_func.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/while_break_func.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,5 @@
+before while
+before dotcmd
+before function
+before break
+after while
diff -urN nonexistant/sh/dotcmd/out/while_break_subshell.out tests/bin/sh/dotcmd/out/while_break_subshell.out
--- nonexistant/sh/dotcmd/out/while_break_subshell.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/while_break_subshell.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,10 @@
+before while
+before dotcmd
+subshell start
+before break
+after dotcmd, return value: 0
+before dotcmd
+subshell start
+before break
+after dotcmd, return value: 0
+after while
diff -urN nonexistant/sh/dotcmd/out/while_break_until.out tests/bin/sh/dotcmd/out/while_break_until.out
--- nonexistant/sh/dotcmd/out/while_break_until.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/while_break_until.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,12 @@
+before while
+before dotcmd
+before until
+before break
+after until
+after dotcmd, return value: 0
+before dotcmd
+before until
+before break
+after until
+after dotcmd, return value: 0
+after while
diff -urN nonexistant/sh/dotcmd/out/while_break_while.out tests/bin/sh/dotcmd/out/while_break_while.out
--- nonexistant/sh/dotcmd/out/while_break_while.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/while_break_while.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,12 @@
+before while
+before dotcmd
+before while
+before break
+after while
+after dotcmd, return value: 0
+before dotcmd
+before while
+before break
+after while
+after dotcmd, return value: 0
+after while
diff -urN nonexistant/sh/dotcmd/out/while_continue_case.out tests/bin/sh/dotcmd/out/while_continue_case.out
--- nonexistant/sh/dotcmd/out/while_continue_case.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/while_continue_case.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+before while
+before dotcmd
+before case
+before continue
+before dotcmd
+before case
+before continue
+after while
diff -urN nonexistant/sh/dotcmd/out/while_continue_compound.out tests/bin/sh/dotcmd/out/while_continue_compound.out
--- nonexistant/sh/dotcmd/out/while_continue_compound.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/while_continue_compound.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+before while
+before dotcmd
+compound start
+before continue
+before dotcmd
+compound start
+before continue
+after while
diff -urN nonexistant/sh/dotcmd/out/while_continue_file.out tests/bin/sh/dotcmd/out/while_continue_file.out
--- nonexistant/sh/dotcmd/out/while_continue_file.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/while_continue_file.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,6 @@
+before while
+before dotcmd
+before continue
+before dotcmd
+before continue
+after while
diff -urN nonexistant/sh/dotcmd/out/while_continue_for.out tests/bin/sh/dotcmd/out/while_continue_for.out
--- nonexistant/sh/dotcmd/out/while_continue_for.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/while_continue_for.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,14 @@
+before while
+before dotcmd
+before for
+before continue
+before continue
+after for
+after dotcmd, return value: 0
+before dotcmd
+before for
+before continue
+before continue
+after for
+after dotcmd, return value: 0
+after while
diff -urN nonexistant/sh/dotcmd/out/while_continue_func.out tests/bin/sh/dotcmd/out/while_continue_func.out
--- nonexistant/sh/dotcmd/out/while_continue_func.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/while_continue_func.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+before while
+before dotcmd
+before function
+before continue
+before dotcmd
+before function
+before continue
+after while
diff -urN nonexistant/sh/dotcmd/out/while_continue_subshell.out tests/bin/sh/dotcmd/out/while_continue_subshell.out
--- nonexistant/sh/dotcmd/out/while_continue_subshell.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/while_continue_subshell.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,10 @@
+before while
+before dotcmd
+subshell start
+before continue
+after dotcmd, return value: 0
+before dotcmd
+subshell start
+before continue
+after dotcmd, return value: 0
+after while
diff -urN nonexistant/sh/dotcmd/out/while_continue_until.out tests/bin/sh/dotcmd/out/while_continue_until.out
--- nonexistant/sh/dotcmd/out/while_continue_until.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/while_continue_until.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,14 @@
+before while
+before dotcmd
+before until
+before continue
+before continue
+after until
+after dotcmd, return value: 0
+before dotcmd
+before until
+before continue
+before continue
+after until
+after dotcmd, return value: 0
+after while
diff -urN nonexistant/sh/dotcmd/out/while_continue_while.out tests/bin/sh/dotcmd/out/while_continue_while.out
--- nonexistant/sh/dotcmd/out/while_continue_while.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/while_continue_while.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,14 @@
+before while
+before dotcmd
+before while
+before continue
+before continue
+after while
+after dotcmd, return value: 0
+before dotcmd
+before while
+before continue
+before continue
+after while
+after dotcmd, return value: 0
+after while
diff -urN nonexistant/sh/dotcmd/out/while_return_case.out tests/bin/sh/dotcmd/out/while_return_case.out
--- nonexistant/sh/dotcmd/out/while_return_case.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/while_return_case.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,10 @@
+before while
+before dotcmd
+before case
+before return
+after dotcmd, return value: 0
+before dotcmd
+before case
+before return
+after dotcmd, return value: 0
+after while
diff -urN nonexistant/sh/dotcmd/out/while_return_compound.out tests/bin/sh/dotcmd/out/while_return_compound.out
--- nonexistant/sh/dotcmd/out/while_return_compound.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/while_return_compound.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,10 @@
+before while
+before dotcmd
+compound start
+before return
+after dotcmd, return value: 0
+before dotcmd
+compound start
+before return
+after dotcmd, return value: 0
+after while
diff -urN nonexistant/sh/dotcmd/out/while_return_file.out tests/bin/sh/dotcmd/out/while_return_file.out
--- nonexistant/sh/dotcmd/out/while_return_file.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/while_return_file.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,8 @@
+before while
+before dotcmd
+before return
+after dotcmd, return value: 0
+before dotcmd
+before return
+after dotcmd, return value: 0
+after while
diff -urN nonexistant/sh/dotcmd/out/while_return_for.out tests/bin/sh/dotcmd/out/while_return_for.out
--- nonexistant/sh/dotcmd/out/while_return_for.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/while_return_for.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,10 @@
+before while
+before dotcmd
+before for
+before return
+after dotcmd, return value: 0
+before dotcmd
+before for
+before return
+after dotcmd, return value: 0
+after while
diff -urN nonexistant/sh/dotcmd/out/while_return_func.out tests/bin/sh/dotcmd/out/while_return_func.out
--- nonexistant/sh/dotcmd/out/while_return_func.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/while_return_func.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,12 @@
+before while
+before dotcmd
+before function
+before return
+after function
+after dotcmd, return value: 0
+before dotcmd
+before function
+before return
+after function
+after dotcmd, return value: 0
+after while
diff -urN nonexistant/sh/dotcmd/out/while_return_subshell.out tests/bin/sh/dotcmd/out/while_return_subshell.out
--- nonexistant/sh/dotcmd/out/while_return_subshell.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/while_return_subshell.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,10 @@
+before while
+before dotcmd
+subshell start
+before return
+after dotcmd, return value: 0
+before dotcmd
+subshell start
+before return
+after dotcmd, return value: 0
+after while
diff -urN nonexistant/sh/dotcmd/out/while_return_until.out tests/bin/sh/dotcmd/out/while_return_until.out
--- nonexistant/sh/dotcmd/out/while_return_until.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/while_return_until.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,10 @@
+before while
+before dotcmd
+before until
+before return
+after dotcmd, return value: 0
+before dotcmd
+before until
+before return
+after dotcmd, return value: 0
+after while
diff -urN nonexistant/sh/dotcmd/out/while_return_while.out tests/bin/sh/dotcmd/out/while_return_while.out
--- nonexistant/sh/dotcmd/out/while_return_while.out 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/out/while_return_while.out 2014-05-28 16:45:08.000000000 +0300
@@ -0,0 +1,10 @@
+before while
+before dotcmd
+before while
+before return
+after dotcmd, return value: 0
+before dotcmd
+before while
+before return
+after dotcmd, return value: 0
+after while
diff -urN nonexistant/sh/dotcmd/scoped_command tests/bin/sh/dotcmd/scoped_command
--- nonexistant/sh/dotcmd/scoped_command 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/scoped_command 2014-05-28 13:44:29.000000000 +0300
@@ -0,0 +1,129 @@
+#!/bin/sh
+#
+# $NetBSD$
+#
+# Copyright (c) 2014 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# This code is derived from software contributed to The NetBSD Foundation
+# by Jarmo Jaakkola.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+set -e
+
+# USAGE:
+# scoped_command scope cmd msg var_suffix
+#
+# Write to stdout a piece of Bourne Shell script with _cmd_ in specific
+# _scope_. The execution of _cmd_ is bracketed by prints of "before _msg_"
+# and "after _msg_, return value ${?}". If the generated script uses
+# variables, __var_suffix_ is appended to their names to allow nesting of
+# scripts generated this way.
+#
+# _scope_ should be one of: case, compound, file, for, func, subshell,
+# until, while.
+# _cmd_ is the command line to execute. Remember proper quoting!
+# _msg_ is text that will be used inside single quotes.
+# _var_suffix_ is a syntactically valid identifier name.
+
+# don't rely on command lists (';')
+cmd="echo 'before ${3}'
+${2}
+echo 'after ${3}, return value:' ${?}"
+
+echo "#!/bin/sh"
+
+[ 'func' = "${1}" ] && cat <<EOF
+func()
+{
+ echo 'before ${3}'
+ \${1}
+ echo 'after ${3}'
+}
+
+echo 'before function'
+func "${2}" "${3}" # don't rely on 'shift'
+echo 'after function'
+EOF
+
+[ 'case' = "${1}" ] && cat <<EOF
+echo 'before case'
+case 'a' in
+ a) ${cmd};;
+esac
+echo 'after case'
+EOF
+
+[ 'file' = "${1}" ] && cat <<EOF
+${cmd}
+EOF
+
+[ 'while' = "${1}" ] && cat <<EOF
+echo 'before while'
+cond_${4}='true true false'
+while \${cond_${4}}
+do
+ cond_${4}="\${cond_${4}#* }"
+ ${cmd}
+done
+echo 'after while'
+EOF
+
+[ 'until' = "${1}" ] && cat <<EOF
+echo 'before until'
+cond_${4}='false false true'
+until \${cond_${4}}
+do
+ cond_${4}="\${cond_${4}#* }"
+ ${cmd}
+done
+echo 'after until'
+EOF
+
+[ 'for' = "${1}" ] && cat <<EOF
+echo 'before for'
+for i_${4} in 1 2
+do
+ ${cmd}
+done
+echo 'after for'
+EOF
+
+[ 'subshell' = "${1}" ] && cat <<EOF
+(
+ echo 'subshell start'
+ ${cmd}
+ echo 'subshell end'
+)
+EOF
+
+[ 'compound' = "${1}" ] && cat <<EOF
+{
+ echo 'compound start'
+ ${cmd};
+ echo 'compound end'
+}
+EOF
+
+exit 0
diff -urN nonexistant/sh/dotcmd/t_dotcmd.sh tests/bin/sh/dotcmd/t_dotcmd.sh
--- nonexistant/sh/dotcmd/t_dotcmd.sh 1970-01-01 02:00:00.000000000 +0200
+++ tests/bin/sh/dotcmd/t_dotcmd.sh 2014-05-28 13:23:27.000000000 +0300
@@ -0,0 +1,76 @@
+# $NetBSD$
+#
+# Copyright (c) 2014 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# This code is derived from software contributed to The NetBSD Foundation
+# by Jarmo Jaakkola.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+# Test loop and function flow control statements in various scopes in a file
+# sourced by a dotcmd in various scopes. Basically, dotcmd is like #include
+# in C/C++ so, for example, if the dotcmd is in a loop's body, a break in
+# the sourced file can be used to break out of that loop.
+
+cmds='return break continue'
+scopes='case compound file for func subshell until while'
+
+case_ids=''
+
+for dot_scope in ${scopes}
+do
+ for cmd in ${cmds}
+ do
+ for cmd_scope in ${scopes}
+ do
+ case_id="${dot_scope}_${cmd}_${cmd_scope}"
+ case_ids="${case_ids} ${case_id}"
+ atf_test_case "${case_id}"
+ eval "
+${case_id}_head()
+{
+ atf_set 'descr' \\
+ 'dotcmd in ${dot_scope}, file contains ${cmd} in ${cmd_scope}'
+}
+
+${case_id}_body()
+{
+ srcdir=\$(atf_get_srcdir)
+ # for dotcmd to find the sourced files
+ PATH=\"\${PATH}:\${srcdir}\"
+ atf_check -o file:\"\${srcdir}/out/${case_id}.out\" \\
+ \"\${srcdir}/${case_id}\"
+}
+" # end eval
+ done
+ done
+done
+
+atf_init_test_cases()
+{
+ for case_id in ${case_ids}
+ do
+ atf_add_test_case "${case_id}"
+ done
+}
From: "Christos Zoulas" <christos@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/48843 CVS commit: src/tests/bin/sh
Date: Sat, 31 May 2014 10:29:07 -0400
Module Name: src
Committed By: christos
Date: Sat May 31 14:29:06 UTC 2014
Modified Files:
src/tests/bin/sh: Makefile
Added Files:
src/tests/bin/sh/dotcmd: Makefile scoped_command t_dotcmd.sh
src/tests/bin/sh/dotcmd/out: case_break_case.out
case_break_compound.out case_break_file.out case_break_for.out
case_break_func.out case_break_subshell.out case_break_until.out
case_break_while.out case_continue_case.out
case_continue_compound.out case_continue_file.out
case_continue_for.out case_continue_func.out
case_continue_subshell.out case_continue_until.out
case_continue_while.out case_return_case.out
case_return_compound.out case_return_file.out case_return_for.out
case_return_func.out case_return_subshell.out case_return_until.out
case_return_while.out compound_break_case.out
compound_break_compound.out compound_break_file.out
compound_break_for.out compound_break_func.out
compound_break_subshell.out compound_break_until.out
compound_break_while.out compound_continue_case.out
compound_continue_compound.out compound_continue_file.out
compound_continue_for.out compound_continue_func.out
compound_continue_subshell.out compound_continue_until.out
compound_continue_while.out compound_return_case.out
compound_return_compound.out compound_return_file.out
compound_return_for.out compound_return_func.out
compound_return_subshell.out compound_return_until.out
compound_return_while.out file_break_case.out
file_break_compound.out file_break_file.out file_break_for.out
file_break_func.out file_break_subshell.out file_break_until.out
file_break_while.out file_continue_case.out
file_continue_compound.out file_continue_file.out
file_continue_for.out file_continue_func.out
file_continue_subshell.out file_continue_until.out
file_continue_while.out file_return_case.out
file_return_compound.out file_return_file.out file_return_for.out
file_return_func.out file_return_subshell.out file_return_until.out
file_return_while.out for_break_case.out for_break_compound.out
for_break_file.out for_break_for.out for_break_func.out
for_break_subshell.out for_break_until.out for_break_while.out
for_continue_case.out for_continue_compound.out
for_continue_file.out for_continue_for.out for_continue_func.out
for_continue_subshell.out for_continue_until.out
for_continue_while.out for_return_case.out for_return_compound.out
for_return_file.out for_return_for.out for_return_func.out
for_return_subshell.out for_return_until.out for_return_while.out
func_break_case.out func_break_compound.out func_break_file.out
func_break_for.out func_break_func.out func_break_subshell.out
func_break_until.out func_break_while.out func_continue_case.out
func_continue_compound.out func_continue_file.out
func_continue_for.out func_continue_func.out
func_continue_subshell.out func_continue_until.out
func_continue_while.out func_return_case.out
func_return_compound.out func_return_file.out func_return_for.out
func_return_func.out func_return_subshell.out func_return_until.out
func_return_while.out subshell_break_case.out
subshell_break_compound.out subshell_break_file.out
subshell_break_for.out subshell_break_func.out
subshell_break_subshell.out subshell_break_until.out
subshell_break_while.out subshell_continue_case.out
subshell_continue_compound.out subshell_continue_file.out
subshell_continue_for.out subshell_continue_func.out
subshell_continue_subshell.out subshell_continue_until.out
subshell_continue_while.out subshell_return_case.out
subshell_return_compound.out subshell_return_file.out
subshell_return_for.out subshell_return_func.out
subshell_return_subshell.out subshell_return_until.out
subshell_return_while.out until_break_case.out
until_break_compound.out until_break_file.out until_break_for.out
until_break_func.out until_break_subshell.out until_break_until.out
until_break_while.out until_continue_case.out
until_continue_compound.out until_continue_file.out
until_continue_for.out until_continue_func.out
until_continue_subshell.out until_continue_until.out
until_continue_while.out until_return_case.out
until_return_compound.out until_return_file.out
until_return_for.out until_return_func.out
until_return_subshell.out until_return_until.out
until_return_while.out while_break_case.out
while_break_compound.out while_break_file.out while_break_for.out
while_break_func.out while_break_subshell.out while_break_until.out
while_break_while.out while_continue_case.out
while_continue_compound.out while_continue_file.out
while_continue_for.out while_continue_func.out
while_continue_subshell.out while_continue_until.out
while_continue_while.out while_return_case.out
while_return_compound.out while_return_file.out
while_return_for.out while_return_func.out
while_return_subshell.out while_return_until.out
while_return_while.out
Log Message:
PR/48843: Jarmo Jaakkola: Test cses for break/continue/return broken
inside dot commands:
The test cases are named with the pattern
dotscope_cmd_cmdscope,
where dotscope is the scope in which the dot command is and cmdscope
is the scope where cmd is in the sourced file.
To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 src/tests/bin/sh/Makefile
cvs rdiff -u -r0 -r1.1 src/tests/bin/sh/dotcmd/Makefile \
src/tests/bin/sh/dotcmd/scoped_command \
src/tests/bin/sh/dotcmd/t_dotcmd.sh
cvs rdiff -u -r0 -r1.1 src/tests/bin/sh/dotcmd/out/case_break_case.out \
src/tests/bin/sh/dotcmd/out/case_break_compound.out \
src/tests/bin/sh/dotcmd/out/case_break_file.out \
src/tests/bin/sh/dotcmd/out/case_break_for.out \
src/tests/bin/sh/dotcmd/out/case_break_func.out \
src/tests/bin/sh/dotcmd/out/case_break_subshell.out \
src/tests/bin/sh/dotcmd/out/case_break_until.out \
src/tests/bin/sh/dotcmd/out/case_break_while.out \
src/tests/bin/sh/dotcmd/out/case_continue_case.out \
src/tests/bin/sh/dotcmd/out/case_continue_compound.out \
src/tests/bin/sh/dotcmd/out/case_continue_file.out \
src/tests/bin/sh/dotcmd/out/case_continue_for.out \
src/tests/bin/sh/dotcmd/out/case_continue_func.out \
src/tests/bin/sh/dotcmd/out/case_continue_subshell.out \
src/tests/bin/sh/dotcmd/out/case_continue_until.out \
src/tests/bin/sh/dotcmd/out/case_continue_while.out \
src/tests/bin/sh/dotcmd/out/case_return_case.out \
src/tests/bin/sh/dotcmd/out/case_return_compound.out \
src/tests/bin/sh/dotcmd/out/case_return_file.out \
src/tests/bin/sh/dotcmd/out/case_return_for.out \
src/tests/bin/sh/dotcmd/out/case_return_func.out \
src/tests/bin/sh/dotcmd/out/case_return_subshell.out \
src/tests/bin/sh/dotcmd/out/case_return_until.out \
src/tests/bin/sh/dotcmd/out/case_return_while.out \
src/tests/bin/sh/dotcmd/out/compound_break_case.out \
src/tests/bin/sh/dotcmd/out/compound_break_compound.out \
src/tests/bin/sh/dotcmd/out/compound_break_file.out \
src/tests/bin/sh/dotcmd/out/compound_break_for.out \
src/tests/bin/sh/dotcmd/out/compound_break_func.out \
src/tests/bin/sh/dotcmd/out/compound_break_subshell.out \
src/tests/bin/sh/dotcmd/out/compound_break_until.out \
src/tests/bin/sh/dotcmd/out/compound_break_while.out \
src/tests/bin/sh/dotcmd/out/compound_continue_case.out \
src/tests/bin/sh/dotcmd/out/compound_continue_compound.out \
src/tests/bin/sh/dotcmd/out/compound_continue_file.out \
src/tests/bin/sh/dotcmd/out/compound_continue_for.out \
src/tests/bin/sh/dotcmd/out/compound_continue_func.out \
src/tests/bin/sh/dotcmd/out/compound_continue_subshell.out \
src/tests/bin/sh/dotcmd/out/compound_continue_until.out \
src/tests/bin/sh/dotcmd/out/compound_continue_while.out \
src/tests/bin/sh/dotcmd/out/compound_return_case.out \
src/tests/bin/sh/dotcmd/out/compound_return_compound.out \
src/tests/bin/sh/dotcmd/out/compound_return_file.out \
src/tests/bin/sh/dotcmd/out/compound_return_for.out \
src/tests/bin/sh/dotcmd/out/compound_return_func.out \
src/tests/bin/sh/dotcmd/out/compound_return_subshell.out \
src/tests/bin/sh/dotcmd/out/compound_return_until.out \
src/tests/bin/sh/dotcmd/out/compound_return_while.out \
src/tests/bin/sh/dotcmd/out/file_break_case.out \
src/tests/bin/sh/dotcmd/out/file_break_compound.out \
src/tests/bin/sh/dotcmd/out/file_break_file.out \
src/tests/bin/sh/dotcmd/out/file_break_for.out \
src/tests/bin/sh/dotcmd/out/file_break_func.out \
src/tests/bin/sh/dotcmd/out/file_break_subshell.out \
src/tests/bin/sh/dotcmd/out/file_break_until.out \
src/tests/bin/sh/dotcmd/out/file_break_while.out \
src/tests/bin/sh/dotcmd/out/file_continue_case.out \
src/tests/bin/sh/dotcmd/out/file_continue_compound.out \
src/tests/bin/sh/dotcmd/out/file_continue_file.out \
src/tests/bin/sh/dotcmd/out/file_continue_for.out \
src/tests/bin/sh/dotcmd/out/file_continue_func.out \
src/tests/bin/sh/dotcmd/out/file_continue_subshell.out \
src/tests/bin/sh/dotcmd/out/file_continue_until.out \
src/tests/bin/sh/dotcmd/out/file_continue_while.out \
src/tests/bin/sh/dotcmd/out/file_return_case.out \
src/tests/bin/sh/dotcmd/out/file_return_compound.out \
src/tests/bin/sh/dotcmd/out/file_return_file.out \
src/tests/bin/sh/dotcmd/out/file_return_for.out \
src/tests/bin/sh/dotcmd/out/file_return_func.out \
src/tests/bin/sh/dotcmd/out/file_return_subshell.out \
src/tests/bin/sh/dotcmd/out/file_return_until.out \
src/tests/bin/sh/dotcmd/out/file_return_while.out \
src/tests/bin/sh/dotcmd/out/for_break_case.out \
src/tests/bin/sh/dotcmd/out/for_break_compound.out \
src/tests/bin/sh/dotcmd/out/for_break_file.out \
src/tests/bin/sh/dotcmd/out/for_break_for.out \
src/tests/bin/sh/dotcmd/out/for_break_func.out \
src/tests/bin/sh/dotcmd/out/for_break_subshell.out \
src/tests/bin/sh/dotcmd/out/for_break_until.out \
src/tests/bin/sh/dotcmd/out/for_break_while.out \
src/tests/bin/sh/dotcmd/out/for_continue_case.out \
src/tests/bin/sh/dotcmd/out/for_continue_compound.out \
src/tests/bin/sh/dotcmd/out/for_continue_file.out \
src/tests/bin/sh/dotcmd/out/for_continue_for.out \
src/tests/bin/sh/dotcmd/out/for_continue_func.out \
src/tests/bin/sh/dotcmd/out/for_continue_subshell.out \
src/tests/bin/sh/dotcmd/out/for_continue_until.out \
src/tests/bin/sh/dotcmd/out/for_continue_while.out \
src/tests/bin/sh/dotcmd/out/for_return_case.out \
src/tests/bin/sh/dotcmd/out/for_return_compound.out \
src/tests/bin/sh/dotcmd/out/for_return_file.out \
src/tests/bin/sh/dotcmd/out/for_return_for.out \
src/tests/bin/sh/dotcmd/out/for_return_func.out \
src/tests/bin/sh/dotcmd/out/for_return_subshell.out \
src/tests/bin/sh/dotcmd/out/for_return_until.out \
src/tests/bin/sh/dotcmd/out/for_return_while.out \
src/tests/bin/sh/dotcmd/out/func_break_case.out \
src/tests/bin/sh/dotcmd/out/func_break_compound.out \
src/tests/bin/sh/dotcmd/out/func_break_file.out \
src/tests/bin/sh/dotcmd/out/func_break_for.out \
src/tests/bin/sh/dotcmd/out/func_break_func.out \
src/tests/bin/sh/dotcmd/out/func_break_subshell.out \
src/tests/bin/sh/dotcmd/out/func_break_until.out \
src/tests/bin/sh/dotcmd/out/func_break_while.out \
src/tests/bin/sh/dotcmd/out/func_continue_case.out \
src/tests/bin/sh/dotcmd/out/func_continue_compound.out \
src/tests/bin/sh/dotcmd/out/func_continue_file.out \
src/tests/bin/sh/dotcmd/out/func_continue_for.out \
src/tests/bin/sh/dotcmd/out/func_continue_func.out \
src/tests/bin/sh/dotcmd/out/func_continue_subshell.out \
src/tests/bin/sh/dotcmd/out/func_continue_until.out \
src/tests/bin/sh/dotcmd/out/func_continue_while.out \
src/tests/bin/sh/dotcmd/out/func_return_case.out \
src/tests/bin/sh/dotcmd/out/func_return_compound.out \
src/tests/bin/sh/dotcmd/out/func_return_file.out \
src/tests/bin/sh/dotcmd/out/func_return_for.out \
src/tests/bin/sh/dotcmd/out/func_return_func.out \
src/tests/bin/sh/dotcmd/out/func_return_subshell.out \
src/tests/bin/sh/dotcmd/out/func_return_until.out \
src/tests/bin/sh/dotcmd/out/func_return_while.out \
src/tests/bin/sh/dotcmd/out/subshell_break_case.out \
src/tests/bin/sh/dotcmd/out/subshell_break_compound.out \
src/tests/bin/sh/dotcmd/out/subshell_break_file.out \
src/tests/bin/sh/dotcmd/out/subshell_break_for.out \
src/tests/bin/sh/dotcmd/out/subshell_break_func.out \
src/tests/bin/sh/dotcmd/out/subshell_break_subshell.out \
src/tests/bin/sh/dotcmd/out/subshell_break_until.out \
src/tests/bin/sh/dotcmd/out/subshell_break_while.out \
src/tests/bin/sh/dotcmd/out/subshell_continue_case.out \
src/tests/bin/sh/dotcmd/out/subshell_continue_compound.out \
src/tests/bin/sh/dotcmd/out/subshell_continue_file.out \
src/tests/bin/sh/dotcmd/out/subshell_continue_for.out \
src/tests/bin/sh/dotcmd/out/subshell_continue_func.out \
src/tests/bin/sh/dotcmd/out/subshell_continue_subshell.out \
src/tests/bin/sh/dotcmd/out/subshell_continue_until.out \
src/tests/bin/sh/dotcmd/out/subshell_continue_while.out \
src/tests/bin/sh/dotcmd/out/subshell_return_case.out \
src/tests/bin/sh/dotcmd/out/subshell_return_compound.out \
src/tests/bin/sh/dotcmd/out/subshell_return_file.out \
src/tests/bin/sh/dotcmd/out/subshell_return_for.out \
src/tests/bin/sh/dotcmd/out/subshell_return_func.out \
src/tests/bin/sh/dotcmd/out/subshell_return_subshell.out \
src/tests/bin/sh/dotcmd/out/subshell_return_until.out \
src/tests/bin/sh/dotcmd/out/subshell_return_while.out \
src/tests/bin/sh/dotcmd/out/until_break_case.out \
src/tests/bin/sh/dotcmd/out/until_break_compound.out \
src/tests/bin/sh/dotcmd/out/until_break_file.out \
src/tests/bin/sh/dotcmd/out/until_break_for.out \
src/tests/bin/sh/dotcmd/out/until_break_func.out \
src/tests/bin/sh/dotcmd/out/until_break_subshell.out \
src/tests/bin/sh/dotcmd/out/until_break_until.out \
src/tests/bin/sh/dotcmd/out/until_break_while.out \
src/tests/bin/sh/dotcmd/out/until_continue_case.out \
src/tests/bin/sh/dotcmd/out/until_continue_compound.out \
src/tests/bin/sh/dotcmd/out/until_continue_file.out \
src/tests/bin/sh/dotcmd/out/until_continue_for.out \
src/tests/bin/sh/dotcmd/out/until_continue_func.out \
src/tests/bin/sh/dotcmd/out/until_continue_subshell.out \
src/tests/bin/sh/dotcmd/out/until_continue_until.out \
src/tests/bin/sh/dotcmd/out/until_continue_while.out \
src/tests/bin/sh/dotcmd/out/until_return_case.out \
src/tests/bin/sh/dotcmd/out/until_return_compound.out \
src/tests/bin/sh/dotcmd/out/until_return_file.out \
src/tests/bin/sh/dotcmd/out/until_return_for.out \
src/tests/bin/sh/dotcmd/out/until_return_func.out \
src/tests/bin/sh/dotcmd/out/until_return_subshell.out \
src/tests/bin/sh/dotcmd/out/until_return_until.out \
src/tests/bin/sh/dotcmd/out/until_return_while.out \
src/tests/bin/sh/dotcmd/out/while_break_case.out \
src/tests/bin/sh/dotcmd/out/while_break_compound.out \
src/tests/bin/sh/dotcmd/out/while_break_file.out \
src/tests/bin/sh/dotcmd/out/while_break_for.out \
src/tests/bin/sh/dotcmd/out/while_break_func.out \
src/tests/bin/sh/dotcmd/out/while_break_subshell.out \
src/tests/bin/sh/dotcmd/out/while_break_until.out \
src/tests/bin/sh/dotcmd/out/while_break_while.out \
src/tests/bin/sh/dotcmd/out/while_continue_case.out \
src/tests/bin/sh/dotcmd/out/while_continue_compound.out \
src/tests/bin/sh/dotcmd/out/while_continue_file.out \
src/tests/bin/sh/dotcmd/out/while_continue_for.out \
src/tests/bin/sh/dotcmd/out/while_continue_func.out \
src/tests/bin/sh/dotcmd/out/while_continue_subshell.out \
src/tests/bin/sh/dotcmd/out/while_continue_until.out \
src/tests/bin/sh/dotcmd/out/while_continue_while.out \
src/tests/bin/sh/dotcmd/out/while_return_case.out \
src/tests/bin/sh/dotcmd/out/while_return_compound.out \
src/tests/bin/sh/dotcmd/out/while_return_file.out \
src/tests/bin/sh/dotcmd/out/while_return_for.out \
src/tests/bin/sh/dotcmd/out/while_return_func.out \
src/tests/bin/sh/dotcmd/out/while_return_subshell.out \
src/tests/bin/sh/dotcmd/out/while_return_until.out \
src/tests/bin/sh/dotcmd/out/while_return_while.out
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
From: "Christos Zoulas" <christos@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/48843 CVS commit: src/bin/sh
Date: Sat, 31 May 2014 10:42:19 -0400
Module Name: src
Committed By: christos
Date: Sat May 31 14:42:18 UTC 2014
Modified Files:
src/bin/sh: eval.c eval.h main.c sh.1
Log Message:
PR/48843: Jarmo Jaakkola: dot commands mess up scope nesting tracking
Evaluation of commands goes completely haywire if a file containing
a break/continue/return command outside its "intended" scope is sourced
using a dot command inside its "intended" scope. The main symptom is
not exiting from the sourced file when supposed to, leading to evaluation
of commands that were not supposed to be evaluated. A secondary symptom
is that these extra commands are not evaluated correctly, as some of them
are skipped. Some examples are listed in the How-To-Repeat section.
According to the POSIX standard, this is how it should work:
dot:
The shell shall execute commands from the file in the current
environment.
break:
The break utility shall exit from the smallest enclosing for, while,
or until loop, [...]
continue:
The continue utility shall return to the top of the smallest
enclosing for, while, or until loop, [...]
return:
The return utility shall cause the shell to stop executing
the current function or dot script. If the shell is not currently
executing a function or dot script, the results are unspecified.
It is clear that return should return from a sourced file, which
it does not do. Whether break and continue should work from the sourced
file might be debatable. Because the dot command says "in the current
environment", I'd say yes. In any case, it should not fail in weird
ways like it does now!
The problems occur with return (a) and break/continue (b) because:
1) dotcmd() does not record the function nesting level prior to
sourcing the file nor does it touch the loopnest variable,
leading to either
2 a) returncmd() being unable to detect that it should not set
evalskip to SKIPFUNC but SKIPFILE, or
b) breakcmd() setting evalskip to SKIPCONT or SKIPBREAK,
leading to
3) cmdloop() not detecting that it should skip the rest of
the file, due to only checking for SKIPFILE.
The result is that cmdloop() keeps executing lines from the file
whilst evalskip is set, which is the main symptom. Because
evalskip is checked in multiple places in eval.c, the secondary
symptom appears.
>How-To-Repeat:
Run the following script:
printf "break\necho break1; echo break2" >break
printf "continue\necho continue1; echo continue2" >continue
printf "return\necho return1; echo return2" >return
while true; do . ./break; done
for i in 1 2; do . ./continue; done
func() {
. ./return
}
func
No output should be produced, but instead this is the result:
break1
continue1
continue1
return1
The main symptom is evident from the unexpected output and the secondary
one from the fact that there are no lines with '2' in them.
>Fix:
Here is patch to src/bin/sh to fix the above problems. It keeps
track of the function nesting level at the beginning of a dot command
to enable the return command to work properly.
I also changed the undefined-by-standard functionality of the return
command when it's not in a dot command or function from (indirectly)
exiting the shell to being silently ignored. This was done because
the previous way has at least one bug: the shell exits without asking
for confirmation when there are stopped jobs.
Because I read the standard to mean that break and continue should have
an effect outside the sourced file, that's how I implemented it. For what
it's worth, this also seems to be what bash does. Also laziness, because
this way required no changes to loopnesting tracking. If this is not
wanted, it might make sense to move the nesting tracking to the inputfile
stack.
The patch also does some clean-up to reduce the amount of global
variables by moving the dotcmd() and the find_dot_file() functions from
main.c to eval.c and making in_function() a proper function.
To generate a diff of this commit:
cvs rdiff -u -r1.108 -r1.109 src/bin/sh/eval.c
cvs rdiff -u -r1.15 -r1.16 src/bin/sh/eval.h
cvs rdiff -u -r1.57 -r1.58 src/bin/sh/main.c
cvs rdiff -u -r1.112 -r1.113 src/bin/sh/sh.1
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
From: Richard Hansen <rhansen@bbn.com>
To: jarmo.jaakkola@roskakori.fi
Cc: gnats-bugs@NetBSD.org, netbsd-bugs@netbsd.org,
tech-userlevel@NetBSD.org
Subject: Re: bin/48843: sh(1): break/continue/return broken inside dot commands
Date: Sat, 31 May 2014 17:14:26 -0400
> According to the POSIX standard, this is how it should work:
> dot:
> The shell shall execute commands from the file in the current
> environment.
> break:
> The break utility shall exit from the smallest enclosing for, while,
> or until loop, [...]
> continue:
> The continue utility shall return to the top of the smallest
> enclosing for, while, or until loop, [...]
> return:
> The return utility shall cause the shell to stop executing
> the current function or dot script. If the shell is not currently
> executing a function or dot script, the results are unspecified.
>
> It is clear that return should return from a sourced file,
Yes.
> Whether break and continue should work from the sourced
> file might be debatable. Because the dot command says "in the current
> environment", I'd say yes.
Not necessarily. POSIX does not define "enclosing loop", so it could be
interpreted as syntactic enclosure (a break/continue command must be a
command in the compound list associated with the loop for the loop to
qualify as enclosing the command) or logical enclosure as experienced
during execution. I can see pros and cons to either behavior.
I will bring this up during the next Austin Group teleconference. We
should be able to get some improved wording in before POSIX Issue 7 TC2
is published (even if that wording is simply "unspecified" or
"implementation defined"). Any input from the NetBSD community would be
appreciated.
The intended behavior of break/continue outside of a loop is also
unclear. I'll bring that up as well.
> Because I read the standard to mean that break and continue should have
> an effect outside the sourced file, that's how I implemented it. For what
> it's worth, this also seems to be what bash does.
The behavior of existing implementations will strongly influence the
direction the Austin Group takes when revising the text. With that
said, what behavior would you like POSIX to specify?
Sourcing a file with the dot command and running a function are very
similar; how do your changes affect how the shell behaves when calling a
function that has break/continue in the body?
> +A non-obvious consequence of the file executing in the current environment
> +is that loop control keywords (continue and break) can be used in the file
> +to control loops surrounding the dot command.
Specifying this new behavior in the man page implies commitment to it.
In case you want to change the behavior in the future (perhaps because
the Austin Group standardizes a different behavior), I would recommend
softening the language like you did with 'return' (e.g., "the POSIX
standard is unclear, so this implementation (currently) does...").
> +The effects of using a return command outside a function or a dot command
> +are not standardized.
One can argue that the effects are standardized as "unspecified". :)
How about: "The POSIX standard says that the results of running 'return'
outside a function or dot script are unspecified. This implementation..."
Thanks,
Richard
From: Jarmo Jaakkola <jarmo.jaakkola@roskakori.fi>
To: Richard Hansen <rhansen@bbn.com>
Cc: gnats-bugs@NetBSD.org, netbsd-bugs@netbsd.org,
tech-userlevel@NetBSD.org
Subject: Re: bin/48843: sh(1): break/continue/return broken inside dot
commands
Date: Sun, 1 Jun 2014 02:09:41 +0300
On Sat, May 31, 2014 at 05:14:26PM -0400, Richard Hansen wrote:
> I will bring this up during the next Austin Group teleconference. We
> should be able to get some improved wording in before POSIX Issue 7 TC2
> is published (even if that wording is simply "unspecified" or
> "implementation defined"). Any input from the NetBSD community would be
> appreciated.
>
> The intended behavior of break/continue outside of a loop is also
> unclear. I'll bring that up as well.
That would be great, these things really should be clarified. This
probably belongs to "shell execution environment"? That is, whether
function and loop nesting levels are part of it or not. How about local
variables, or were they just a common extension that is not specified
in POSIX?
While we're on the subject of clarity, I'm not sure if the value $0
inside a dot command has been specified. It could be implied by
"current execution environment" but perhaps it wouldn't hurt to be
explicit.
> > Because I read the standard to mean that break and continue should have
> > an effect outside the sourced file, that's how I implemented it. For what
> > it's worth, this also seems to be what bash does.
>
> The behavior of existing implementations will strongly influence the
> direction the Austin Group takes when revising the text. With that
> said, what behavior would you like POSIX to specify?
I have no opinion one way or another. I just took the easiest way to fix
existing breakage. I quickly tested with bash, ksh and zsh with a trivial
case: dot command in a while loop contains a break. bash does as my change
does: the loop is broken. ksh complains and seems to ignore the break.
zsh's behaviour is probably best described as "undefined", because it
complains, stops sourcing the file and yet does not break the loop.
> Sourcing a file with the dot command and running a function are very
> similar; how do your changes affect how the shell behaves when calling a
> function that has break/continue in the body?
My changes retain the previous behavior, which was to allow a break or
a continue in function to affect a loop that contains the function call.
Quick check for other shells: bash and zsh work the same, ksh complains and
does not break the loop nor return from the function.
How the function call worked was one more reason I chose to implement
the dot command fix as I did: one could think this implementation of
a dot command as a function call that has no parameters (except "set --")
and that the function's body is stored in a file.
> > +A non-obvious consequence of the file executing in the current environment
> > +is that loop control keywords (continue and break) can be used in the file
> > +to control loops surrounding the dot command.
>
> Specifying this new behavior in the man page implies commitment to it.
> In case you want to change the behavior in the future (perhaps because
> the Austin Group standardizes a different behavior), I would recommend
> softening the language like you did with 'return' (e.g., "the POSIX
> standard is unclear, so this implementation (currently) does...").
I agree, that would be better. Perhaps:
The POSIX standard is unclear on how loop control keywords (break
and continue) behave across a dot command boundary. This
implementation (currently) allows them to control loops surrounding
the dot command.
> > +The effects of using a return command outside a function or a dot command
> > +are not standardized.
>
> One can argue that the effects are standardized as "unspecified". :)
>
> How about: "The POSIX standard says that the results of running 'return'
> outside a function or dot script are unspecified. This implementation..."
Yes, of course, my bad. Your formulation would be better.
christos, you made the previous commits, could you do those language
tweaks? Or should I prepare another patch?
--
Jarmo Jaakkola
From: David Holland <dholland-tech@netbsd.org>
To: Richard Hansen <rhansen@bbn.com>
Cc: jarmo.jaakkola@roskakori.fi, gnats-bugs@NetBSD.org,
tech-userlevel@NetBSD.org
Subject: Re: bin/48843: sh(1): break/continue/return broken inside dot
commands
Date: Sat, 31 May 2014 23:51:35 +0000
On Sat, May 31, 2014 at 05:14:26PM -0400, Richard Hansen wrote:
> > Whether break and continue should work from the sourced
> > file might be debatable. Because the dot command says "in the current
> > environment", I'd say yes.
>
> Not necessarily. POSIX does not define "enclosing loop", so it could be
> interpreted as syntactic enclosure (a break/continue command must be a
> command in the compound list associated with the loop for the loop to
> qualify as enclosing the command) or logical enclosure as experienced
> during execution. I can see pros and cons to either behavior.
Offhand, I would say that continues and breaks should be statically
scoped; dynamic scoping is almost always a mistake. So you certainly
shouldn't be able to break from a loop by calling a function that
contains a break outside a loop. (Although netbsd's sh, bash, and zsh
all seem to allow this, I would call it a bug. ksh rejects it.)
How this applies to a sourced file isn't so clear though, at least
offhand, as the point of sourcing a file is to read and evaluate it
within the current context. My inclination would be that sourcing a
file is not the same as calling a function; however, I'm far from an
expert on sh.
It seems that the behavior of sourcing with respect to $0 and $@
varies among implementations, which doesn't make me happy.
> I will bring this up during the next Austin Group teleconference. We
> should be able to get some improved wording in before POSIX Issue 7 TC2
> is published (even if that wording is simply "unspecified" or
> "implementation defined"). Any input from the NetBSD community would be
> appreciated.
>
> The intended behavior of break/continue outside of a loop is also
> unclear. I'll bring that up as well.
netbsd's sh seems to accept it silently; ksh, bash, and zsh all reject
it. I would consider our sh broken.
> > Because I read the standard to mean that break and continue should have
> > an effect outside the sourced file, that's how I implemented it. For what
> > it's worth, this also seems to be what bash does.
>
> The behavior of existing implementations will strongly influence the
> direction the Austin Group takes when revising the text. With that
> said, what behavior would you like POSIX to specify?
With stuff like this, I'd rather fix our implementation (or have it be
noncompliant until fixed) than standardize unprincipled behavior. FWIW.
--
David A. Holland
dholland@netbsd.org
From: David Holland <dholland-tech@netbsd.org>
To: Richard Hansen <rhansen@bbn.com>, gnats-bugs@NetBSD.org,
tech-userlevel@NetBSD.org
Cc:
Subject: Re: bin/48843: sh(1): break/continue/return broken inside dot
commands
Date: Sat, 31 May 2014 23:55:48 +0000
On Sun, Jun 01, 2014 at 02:09:41AM +0300, Jarmo Jaakkola wrote:
> How the function call worked was one more reason I chose to implement
> the dot command fix as I did: one could think this implementation of
> a dot command as a function call that has no parameters (except "set --")
> and that the function's body is stored in a file.
Well... implementations other than netbsd's sh seem to allow passing
parameters to a dot command:
valkyrie% cat y2
. ./y a b c d e
valkyrie% cat y
echo '$0 is '"$0"'; $@ is '"$@"
valkyrie% sh ./y2
$0 is ./y2; $@ is
valkyrie% ksh ./y2
$0 is ./y2; $@ is a b c d e
valkyrie% bash ./y2
$0 is ./y2; $@ is a b c d e
valkyrie% zsh ./y2
$0 is ./y; $@ is a b c d e
valkyrie%
although apparently only zsh changes $0.
--
David A. Holland
dholland@netbsd.org
From: Jarmo Jaakkola <jarmo.jaakkola@roskakori.fi>
To: gnats-bugs@NetBSD.org
Cc:
Subject: Re: bin/48843: sh(1): break/continue/return broken inside dot
commands
Date: Sun, 1 Jun 2014 19:25:21 +0300
Soften the language in the manual page, making less promises about
behavior not explicitly stated in the standard.
diff -u orig/sh.1 new/sh.1
--- orig/sh.1
+++ new/sh.1
@@ -1193,9 +1193,10 @@ variable if it does not contain a directory separator
.Pq Sq / .
The return command can be used for a premature return from the sourced file.
.Pp
-A non-obvious consequence of the file executing in the current environment
-is that loop control keywords (continue and break) can be used in the file
-to control loops surrounding the dot command.
+The POSIX standard is unclear on how loop control keywords (break
+and continue) behave across a dot command boundary.
+This implementation allows them to control loops surrounding the dot command,
+but obviously such behavior should not be relied on.
.It alias Op Ar name Ns Op Ar "=string ..."
If
.Ar name=string
@@ -1641,11 +1642,13 @@ For portability,
.Ar n
should be in the range from 0 to 255.
.Pp
-The effects of using a return command outside a function or a dot command
-are not standardized.
-This implementation (currently) treats such a return as a no-op with
-a return value of 0 (success, true).
-Use the exit command if you want to return from a script or exit your shell.
+The POSIX standard says that the results of
+.Sq return
+outside a function or a dot command are unspecified.
+This implementation treats such a return as a no-op with a return value of 0
+(success, true).
+Use the exit command instead, if you want to return from a script or exit
+your shell.
.It set Oo { Fl options | Cm +options | Cm \-- } Oc Ar arg ...
The
.Ic set
--
Jarmo Jaakkola
From: "Christos Zoulas" <christos@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/48843 CVS commit: src/bin/sh
Date: Sun, 1 Jun 2014 13:46:06 -0400
Module Name: src
Committed By: christos
Date: Sun Jun 1 17:46:06 UTC 2014
Modified Files:
src/bin/sh: sh.1
Log Message:
PR/48843: Jarmo Jaakkola: Soften the language in the manual page,
making less promises about behavior not explicitly stated in the standard.
To generate a diff of this commit:
cvs rdiff -u -r1.113 -r1.114 src/bin/sh/sh.1
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
From: Rhialto <rhialto@falu.nl>
To: David Holland <dholland-tech@netbsd.org>
Cc: Richard Hansen <rhansen@bbn.com>, jarmo.jaakkola@roskakori.fi,
gnats-bugs@NetBSD.org, tech-userlevel@NetBSD.org
Subject: Re: bin/48843: sh(1): break/continue/return broken inside dot
commands
Date: Sun, 1 Jun 2014 23:19:17 +0200
--nmemrqcdn5VTmUEE
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
On Sat 31 May 2014 at 23:51:35 +0000, David Holland wrote:
> On Sat, May 31, 2014 at 05:14:26PM -0400, Richard Hansen wrote:
> > Not necessarily. POSIX does not define "enclosing loop", so it could =
be
> > interpreted as syntactic enclosure (a break/continue command must be a
> > command in the compound list associated with the loop for the loop to
> > qualify as enclosing the command) or logical enclosure as experienced
> > during execution. I can see pros and cons to either behavior.
>=20
> Offhand, I would say that continues and breaks should be statically
> scoped; dynamic scoping is almost always a mistake. So you certainly
> shouldn't be able to break from a loop by calling a function that
> contains a break outside a loop. (Although netbsd's sh, bash, and zsh
> all seem to allow this, I would call it a bug. ksh rejects it.)
I agree. The other way is clearly unworkable. A function with a break or
continue outside a loop would be incorrect to call except inside a loop.
That is ludicrous.
> How this applies to a sourced file isn't so clear though, at least
> offhand, as the point of sourcing a file is to read and evaluate it
> within the current context. My inclination would be that sourcing a
> file is not the same as calling a function; however, I'm far from an
> expert on sh.
I would say here too that static checking should be the norm. Except
that there is an inherent non-staticness here: the file could have been
generated dynamically, or the name of the file could be dynamic, or
perhaps even more annoying non-static things.
-Olaf.
--=20
___ Olaf 'Rhialto' Seibert -- The Doctor: No, 'eureka' is Greek for
\X/ rhialto/at/xs4all.nl -- 'this bath is too hot.'
--nmemrqcdn5VTmUEE
Content-Type: application/pgp-signature
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQEcBAEBAgAGBQJTi5jUAAoJEJmJxkVhw/vTnnoH/05oc9bPyvEB1mN1UeCxaLZj
n9/fE+KfnguYZq1bZC9kL8nFwvddXdq/NVEDpP67Ie7dvyfSsblK1VYYpP0/+ETX
ITUZFt/iiCsg+wLlejmSD08pWzNaNHBPA4YMe6wX7N/XaL8JWaFZt+0XUW/cRAPE
lRN8H/fzOri5rins4++/NEY30/3Bubw1xUhx7I+mjy1Rjrv3BBpQxA0eEb8n+/Hy
/W2zzXX79AB1uKSLGxJD8k5oAIFy0Zi4QIfc2qZ7HziJ1AWn/hCuhIrOyhQmHHEp
cwItWX4O3vYqmcDyfUtnsGdJn12y2x8dzmSHtoSkCaymPyuh2IQAGpOlJxIWxOc=
=StD5
-----END PGP SIGNATURE-----
--nmemrqcdn5VTmUEE--
From: Richard Hansen <rhansen@bbn.com>
To: gnats-bugs@NetBSD.org, netbsd-bugs@netbsd.org,
tech-userlevel@NetBSD.org
Cc:
Subject: Re: bin/48843: sh(1): break/continue/return broken inside dot commands
Date: Mon, 02 Jun 2014 13:21:17 -0400
On 2014-05-31 19:09, Jarmo Jaakkola wrote:
> On Sat, May 31, 2014 at 05:14:26PM -0400, Richard Hansen wrote:
>> I will bring this up during the next Austin Group teleconference. We
>> should be able to get some improved wording in before POSIX Issue 7 TC2
>> is published (even if that wording is simply "unspecified" or
>> "implementation defined"). Any input from the NetBSD community would be
>> appreciated.
>>
>> The intended behavior of break/continue outside of a loop is also
>> unclear. I'll bring that up as well.
I filed a bug report that will be the basis for discussion during the
Thursday teleconference (assuming we have time to address this bug):
http://austingroupbugs.net/view.php?id=842
>
> That would be great, these things really should be clarified. This
> probably belongs to "shell execution environment"? That is, whether
> function and loop nesting levels are part of it or not.
I'll think about it more when I write up the proposed changes, but I
don't think that the Shell Execution Environment section is the
appropriate place. That section is all about how the shell forks (or
the equivalent) to run commands. The purpose of the "in the current
environment" phrase in the dot command's description is to let you know
that the script isn't run in a subshell or as a separate process, so it
can modify variable assignments, etc.
If dot was meant to act like C's #include and read a separate file's
lines as if they were typed where the dot command was typed, then I
think it would have been specified that way.
> How about local
> variables, or were they just a common extension that is not specified
> in POSIX?
Local variables are a common extension. Proposing text to standardize
local variables is on my todo list -- they would help solve some really
problematic parts of the current standard. See [1] and the discussion
at [2].
I should note that anyone is welcome to submit bug reports or proposed
wording changes about any topic. You can even join the next POSIX
telecon if you'd like; see [3].
[1] http://austingroupbugs.net/view.php?id=654
[2] http://thread.gmane.org/gmane.comp.standards.posix.austin.general/6728
[3] http://article.gmane.org/gmane.comp.standards.posix.austin.general/9454
>
> While we're on the subject of clarity, I'm not sure if the value $0
> inside a dot command has been specified. It could be implied by
> "current execution environment" but perhaps it wouldn't hurt to be
> explicit.
The value of $0 in a dot script is specified -- it is the same as it was
before the script was sourced. This is not explicit -- the only way to
arrive at this conclusion is to note that the description of the dot
command does not specify any change to $0. It would be better if this
was made explicit, as it is with functions. I'll add that to my todo
list, or you can file a bug report if you'd like.
>> The behavior of existing implementations will strongly influence the
>> direction the Austin Group takes when revising the text. With that
>> said, what behavior would you like POSIX to specify?
>
> I have no opinion one way or another. I just took the easiest way to fix
> existing breakage.
OK
> I quickly tested with bash, ksh and zsh with a trivial
> case: dot command in a while loop contains a break. bash does as my change
> does: the loop is broken. ksh complains and seems to ignore the break.
> zsh's behaviour is probably best described as "undefined", because it
> complains, stops sourcing the file and yet does not break the loop.
Curious -- I had different results when testing 'break' from a dot
script in other shells (I documented my results in the POSIX bug report).
>
>> Sourcing a file with the dot command and running a function are very
>> similar; how do your changes affect how the shell behaves when calling a
>> function that has break/continue in the body?
>
> My changes retain the previous behavior, which was to allow a break or
> a continue in function to affect a loop that contains the function call.
So the behavior from a function and the behavior from a dot script are
now the same? I like that.
> Quick check for other shells: bash and zsh work the same, ksh complains and
> does not break the loop nor return from the function.
Hmm, my test results differed from yours in the function case as well as
the dot script case. (Not that it matters much.)
>
> How the function call worked was one more reason I chose to implement
> the dot command fix as I did: one could think this implementation of
> a dot command as a function call that has no parameters (except "set --")
> and that the function's body is stored in a file.
Exactly -- I think it's good for those two cases to be consistent.
-Richard
From: Richard Hansen <rhansen@bbn.com>
To: David Holland <dholland-tech@netbsd.org>
Cc: jarmo.jaakkola@roskakori.fi, gnats-bugs@NetBSD.org,
tech-userlevel@NetBSD.org
Subject: Re: bin/48843: sh(1): break/continue/return broken inside dot commands
Date: Mon, 02 Jun 2014 13:54:04 -0400
On 2014-05-31 19:51, David Holland wrote:
> On Sat, May 31, 2014 at 05:14:26PM -0400, Richard Hansen wrote:
>>> Whether break and continue should work from the sourced
>>> file might be debatable. Because the dot command says "in the current
>>> environment", I'd say yes.
>>
>> Not necessarily. POSIX does not define "enclosing loop", so it could be
>> interpreted as syntactic enclosure (a break/continue command must be a
>> command in the compound list associated with the loop for the loop to
>> qualify as enclosing the command) or logical enclosure as experienced
>> during execution. I can see pros and cons to either behavior.
>
> Offhand, I would say that continues and breaks should be statically
> scoped; dynamic scoping is almost always a mistake. So you certainly
> shouldn't be able to break from a loop by calling a function that
> contains a break outside a loop. (Although netbsd's sh, bash, and zsh
> all seem to allow this, I would call it a bug. ksh rejects it.)
I think I also prefer lexical scoping, but I can see some valid (though
unusual) uses for dynamic scoping.
>
> How this applies to a sourced file isn't so clear though, at least
> offhand, as the point of sourcing a file is to read and evaluate it
> within the current context.
Yes and no -- there are subtle differences between the dot command and
C's #include preprocessor directive (exit status of the dot command,
in-line variable assignments before the dot command, redirection).
> My inclination would be that sourcing a
> file is not the same as calling a function; however, I'm far from an
> expert on sh.
I don't really know the history, but my impression is that the dot
command was intended to make it possible to split common complex tasks
out into modular, reusable scripts. That sounds more like a function
and less like a preprocessor include to me, though the differences
aren't very significant.
>
> It seems that the behavior of sourcing with respect to $0 and $@
> varies among implementations, which doesn't make me happy.
They're all consistent if you don't specify any additional arguments to
the dot command. Zsh does something different with $0, but it's an
incompatible scripting language in many ways unless run in sh emulation
mode (e.g., it doesn't do word splitting by default -- a drastic
departure from POSIX shell).
>
>> I will bring this up during the next Austin Group teleconference. We
>> should be able to get some improved wording in before POSIX Issue 7 TC2
>> is published (even if that wording is simply "unspecified" or
>> "implementation defined"). Any input from the NetBSD community would be
>> appreciated.
>>
>> The intended behavior of break/continue outside of a loop is also
>> unclear. I'll bring that up as well.
>
> netbsd's sh seems to accept it silently; ksh, bash, and zsh all reject
> it. I would consider our sh broken.
Yes, although not necessarily non-conformant. I'd say that the behavior
of break and continue outside of a loop should be specified as
undefined, which would allow implementations to do whatever they want
(error out, silently ignore it, give it a special meaning as a fancy
extension, etc.).
>
>>> Because I read the standard to mean that break and continue should have
>>> an effect outside the sourced file, that's how I implemented it. For what
>>> it's worth, this also seems to be what bash does.
>>
>> The behavior of existing implementations will strongly influence the
>> direction the Austin Group takes when revising the text. With that
>> said, what behavior would you like POSIX to specify?
>
> With stuff like this, I'd rather fix our implementation (or have it be
> noncompliant until fixed) than standardize unprincipled behavior. FWIW.
OK, so that's one one vote for static/lexical scoping.
Note that unlike variable binding, the behavior of dynamic scoping of
break/continue is a superset of static/lexical scoping (assuming no
closures): If the shell does dynamic scoping of break/continue but
scripts are always written assuming lexical scoping then those scripts
will still work as expected in all cases. If POSIX were to specify
static/lexical scoping then a shell that performs dynamic scoping would
be conformant but with an extension to the standard.
-Richard
From: Richard Hansen <rhansen@bbn.com>
To: David Holland <dholland-tech@netbsd.org>
Cc: jarmo.jaakkola@roskakori.fi, gnats-bugs@NetBSD.org,
tech-userlevel@NetBSD.org
Subject: Re: bin/48843: sh(1): break/continue/return broken inside dot commands
Date: Tue, 03 Jun 2014 12:53:56 -0400
On 2014-06-02 13:54, Richard Hansen wrote:
> Note that unlike variable binding, the behavior of dynamic scoping of
> break/continue is a superset of static/lexical scoping (assuming no
> closures): If the shell does dynamic scoping of break/continue but
> scripts are always written assuming lexical scoping then those scripts
> will still work as expected in all cases. If POSIX were to specify
> static/lexical scoping then a shell that performs dynamic scoping would
> be conformant but with an extension to the standard.
Oops -- as pointed out in [1] this is incorrect when the argument to
break/continue is greater than the number of lexically enclosing loops.
An author could write 'break 1000' to make it obvious to other readers
that all loops should be broken. A script like this might behave
differently on a shell that does dynamic scoping vs. a shell that does
lexical scoping.
So it looks like POSIX will probably have to choose either lexical
(static) or dynamic for the next major version of the standard (Issue 8).
David voiced his preference for lexical [2]; does anyone else have an
opinion?
I think my preference is for dynamic, although I would question the
design decisions of a script author that takes advantage of dynamic
scoping. Why dynamic over lexical? Because functionality is lost by
making it lexical: If a script author wants dynamic but the shell does
lexical, the author is out of luck. If the shell does dynamic but the
author wants lexical, the author can easily count the number of
lexically enclosing loops and limit the argument of break/continue to
that value. Dynamic might also be easier to implement.
Thanks,
Richard
[1] http://article.gmane.org/gmane.comp.standards.posix.austin.general/9467
[2] http://article.gmane.org/gmane.os.netbsd.devel.userlevel/17452
From: Aleksej Saushev <asau@inbox.ru>
To: gnats-bugs@netbsd.org
Cc:
Subject: Re: bin/48843: sh(1): break/continue/return broken inside dot commands
Date: Thu, 05 Jun 2014 02:32:01 +0400
Richard Hansen <rhansen@bbn.com> writes:
> The following reply was made to PR bin/48843; it has been noted by GNATS.
>
> From: Richard Hansen <rhansen@bbn.com>
> To: David Holland <dholland-tech@netbsd.org>
> Cc: jarmo.jaakkola@roskakori.fi, gnats-bugs@NetBSD.org,
> tech-userlevel@NetBSD.org
> Subject: Re: bin/48843: sh(1): break/continue/return broken inside dot commands
> Date: Tue, 03 Jun 2014 12:53:56 -0400
>
> On 2014-06-02 13:54, Richard Hansen wrote:
> > Note that unlike variable binding, the behavior of dynamic scoping of
> > break/continue is a superset of static/lexical scoping (assuming no
> > closures): If the shell does dynamic scoping of break/continue but
> > scripts are always written assuming lexical scoping then those scripts
> > will still work as expected in all cases. If POSIX were to specify
> > static/lexical scoping then a shell that performs dynamic scoping would
> > be conformant but with an extension to the standard.
>
> Oops -- as pointed out in [1] this is incorrect when the argument to
> break/continue is greater than the number of lexically enclosing loops.
> An author could write 'break 1000' to make it obvious to other readers
> that all loops should be broken. A script like this might behave
> differently on a shell that does dynamic scoping vs. a shell that does
> lexical scoping.
>
> So it looks like POSIX will probably have to choose either lexical
> (static) or dynamic for the next major version of the standard (Issue 8).
>
> David voiced his preference for lexical [2]; does anyone else have an
> opinion?
>
> I think my preference is for dynamic, although I would question the
> design decisions of a script author that takes advantage of dynamic
> scoping. Why dynamic over lexical? Because functionality is lost by
> making it lexical: If a script author wants dynamic but the shell does
> lexical, the author is out of luck. If the shell does dynamic but the
> author wants lexical, the author can easily count the number of
> lexically enclosing loops and limit the argument of break/continue to
> that value. Dynamic might also be easier to implement.
No, this is wrong. Simulating dynamic scoping with lexical one is clear
and almost trivial. It also has benefit that you have control over which
variables have dynamic scope. The opposite is practically impossible.
Besides, the general consensus in programming languages community is
that dynamic scoping is bad design. It breaks abstractions and thus
makes writing modular and correct code a lot harder. Choosing dynamic
scoping over lexical has nearly disastrous consequences on the code
maintainability.
From: Richard Hansen <rhansen@bbn.com>
To: gnats-bugs@NetBSD.org, netbsd-bugs@netbsd.org,
tech-userlevel@NetBSD.org
Cc:
Subject: Re: bin/48843: sh(1): break/continue/return broken inside dot commands
Date: Thu, 05 Jun 2014 14:56:00 -0400
On 2014-06-02 13:21, Richard Hansen wrote:
>> On Sat, May 31, 2014 at 05:14:26PM -0400, Richard Hansen wrote:
>>> I will bring this up during the next Austin Group teleconference. We
>>> should be able to get some improved wording in before POSIX Issue 7 TC2
>>> is published (even if that wording is simply "unspecified" or
>>> "implementation defined"). Any input from the NetBSD community would be
>>> appreciated.
>>>
>>> The intended behavior of break/continue outside of a loop is also
>>> unclear. I'll bring that up as well.
>
> I filed a bug report that will be the basis for discussion during the
> Thursday teleconference (assuming we have time to address this bug):
> http://austingroupbugs.net/view.php?id=842
That bug has been resolved, with the revised text (which will be in
Issue 7 TC2) available here:
http://austingroupbugs.net/view.php?id=842#c2257
We decided to not do anything for Issue 8 at this time, so the behavior
will continue to be unspecified if n is greater than the number of
lexically enclosing loops. The argument is that the standard has been
this way for 20+ years without any major complaints, so why force
implementations to change their code to support a case that few care about.
-Richard
State-Changed-From-To: open->closed
State-Changed-By: dholland@NetBSD.org
State-Changed-When: Mon, 31 Oct 2016 05:33:09 +0000
State-Changed-Why:
the patches got committed and the standards discussion did not lead to
needing to do further work.
>Unformatted:
(Contact us)
$NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2014
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.