mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
The 'exit' and 'return' commands without an argument failed to pass down the exit status of the last-run command when incorporated in a block with redirection, &&/|| list, 'case' statement, or 'while', 'until' or 'for' loop. src/cmd/ksh93/bltins/cflow.c: - Use $?, which is sh.savexit a.k.a. shp->savexit, as the default exit status value if there is no argument, instead of shp->oldexit. This fixes the default exit status behaviour to match POSIX and other shells. src/cmd/ksh93/include/defs.h, src/cmd/ksh93/include/shell.h: - Remove now-unused sh.oldexit (a.k.a. shp->oldexit) private struct member. It appeared to fulfill the same function as sh.savexit, but in a slightly broken way. - Move the savexit/$? declaration from the _SH_PRIVATE part of the struct definition to the public API part. Since $? uses this, it's clearly a publicly exposed value already, and this is generally the one to use. (If anything, it's exitval that should have been private.) This declares savexit right next to exitval, rewriting the comments to clarify the difference between them. src/cmd/ksh93/sh/fault.c, src/cmd/ksh93/sh/subshell.c, src/cmd/ksh93/sh/xec.c: - Remove assignments to shp->oldexit. src/cmd/ksh93/tests/basic.sh: - Add thorough regression tests for the default exit status behaviour of 'return' and 'exit' in various lexical contexts. - Verify that 'for' and 'case' without any command, as well as a lone redirection, still correctly reset the exit status to 0. Fixes: #117
120 lines
3.8 KiB
C
120 lines
3.8 KiB
C
/***********************************************************************
|
|
* *
|
|
* This software is part of the ast package *
|
|
* Copyright (c) 1982-2012 AT&T Intellectual Property *
|
|
* and is licensed under the *
|
|
* Eclipse Public License, Version 1.0 *
|
|
* by AT&T Intellectual Property *
|
|
* *
|
|
* A copy of the License is available at *
|
|
* http://www.eclipse.org/org/documents/epl-v10.html *
|
|
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
|
|
* *
|
|
* Information and Software Systems Research *
|
|
* AT&T Research *
|
|
* Florham Park NJ *
|
|
* *
|
|
* David Korn <dgk@research.att.com> *
|
|
* *
|
|
***********************************************************************/
|
|
#pragma prototyped
|
|
/*
|
|
* break [n]
|
|
* continue [n]
|
|
* return [n]
|
|
* exit [n]
|
|
*
|
|
* David Korn
|
|
* AT&T Labs
|
|
* dgk@research.att.com
|
|
*
|
|
*/
|
|
|
|
#include "defs.h"
|
|
#include <ast.h>
|
|
#include <error.h>
|
|
#include "shnodes.h"
|
|
#include "builtins.h"
|
|
|
|
/*
|
|
* return and exit
|
|
*/
|
|
#if 0
|
|
/* for the dictionary generator */
|
|
int b_exit(int n, register char *argv[],Shbltin_t *context){}
|
|
#endif
|
|
int b_return(register int n, register char *argv[],Shbltin_t *context)
|
|
{
|
|
register char *arg;
|
|
register Shell_t *shp = context->shp;
|
|
struct checkpt *pp = (struct checkpt*)shp->jmplist;
|
|
const char *options = (**argv=='r'?sh_optreturn:sh_optexit);
|
|
while((n = optget(argv,options))) switch(n)
|
|
{
|
|
case ':':
|
|
if(!strmatch(argv[opt_info.index],"[+-]+([0-9])"))
|
|
errormsg(SH_DICT,2, "%s", opt_info.arg);
|
|
goto done;
|
|
case '?':
|
|
errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
|
|
return(2);
|
|
}
|
|
done:
|
|
if(error_info.errors)
|
|
errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
|
|
pp->mode = (**argv=='e'?SH_JMPEXIT:SH_JMPFUN);
|
|
argv += opt_info.index;
|
|
n = (arg = *argv) ? (int)strtol(arg, (char**)0, 10) : shp->savexit;
|
|
if(n<0 || n==256 || n > SH_EXITMASK+shp->gd->sigmax+1)
|
|
n &= ((unsigned int)n)&SH_EXITMASK;
|
|
/* return outside of function, dotscript and profile is exit */
|
|
if(shp->fn_depth==0 && shp->dot_depth==0 && !sh_isstate(SH_PROFILE))
|
|
pp->mode = SH_JMPEXIT;
|
|
shp->savexit = n;
|
|
sh_exit((pp->mode == SH_JMPEXIT) ? (n & SH_EXITMASK) : n);
|
|
return(1);
|
|
}
|
|
|
|
|
|
/*
|
|
* break and continue
|
|
*/
|
|
#if 0
|
|
/* for the dictionary generator */
|
|
int b_continue(int n, register char *argv[],Shbltin_t *context){}
|
|
#endif
|
|
int b_break(register int n, register char *argv[],Shbltin_t *context)
|
|
{
|
|
char *arg;
|
|
register int cont= **argv=='c';
|
|
register Shell_t *shp = context->shp;
|
|
while((n = optget(argv,cont?sh_optcont:sh_optbreak))) switch(n)
|
|
{
|
|
case ':':
|
|
errormsg(SH_DICT,2, "%s", opt_info.arg);
|
|
break;
|
|
case '?':
|
|
errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
|
|
return(2);
|
|
}
|
|
if(error_info.errors)
|
|
errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
|
|
argv += opt_info.index;
|
|
n=1;
|
|
if(arg= *argv)
|
|
{
|
|
n = (int)strtol(arg,&arg,10);
|
|
if(n<=0 || *arg)
|
|
errormsg(SH_DICT,ERROR_exit(1),e_nolabels,*argv);
|
|
}
|
|
if(shp->st.loopcnt)
|
|
{
|
|
shp->st.execbrk = shp->st.breakcnt = n;
|
|
if(shp->st.breakcnt > shp->st.loopcnt)
|
|
shp->st.breakcnt = shp->st.loopcnt;
|
|
if(cont)
|
|
shp->st.breakcnt = -shp->st.breakcnt;
|
|
}
|
|
return(0);
|
|
}
|
|
|