1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00
cde/src/cmd/ksh93/bltins/cflow.c
Martijn Dekker 092b90da81 Fix BUG_LOOPRET2 and related return/exit misbehaviour
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
2020-09-09 20:02:20 +02:00

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);
}