1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00

Fix ${x=y} and ${x:=y} for numeric types of x

These POSIX expansions first assign y to x if x is unset or empty,
respectively, and then they yield the value of x. This was not
working on any ksh93 version if x was typeset as numeric (integer
or float) but still unset, as in not assigned a value.

$ unset a; typeset -i a; printf '%q\n' "${a:=42}" "$a"
0
''

Expected output:
42
42

src/cmd/ksh93/sh/macro.c:
- Fix the test for set/unset variable. It was broken because it
  only checked for the existence of the node, which exists after
  'typeset', but did not check if a value had been assigned. This
  additional check needs to be done with the nv_isnull() macro, but
  only for expansions of the regular M_BRACE type. Special
  expansions cannot have an unset state.
- As of commit 95294419, we know that an nv_optimize() call may be
  needed before using nv_isnull() if the shell is compiled with
  SHOPT_OPTIMIZE. Move the nv_optimize() call from that commit
  forward to before the new check that calls nv_isnull(), and only
  bother with it if the type is M_BRACE.

src/cmd/ksh93/tests/variables.sh:
- Add tests for this bug. Test float and integer, and also check
  that ${a=b} and ${a:=b} correctly treat the value of 'b' as an
  arithmetic expression of which the result is assigned to 'a' if
  'a' was typeset as numeric.

src/cmd/ksh93/tests/attributes.sh,
src/cmd/ksh93/tests/comvar.sh,
src/cmd/ksh93/tests/nameref.sh,
src/cmd/ksh93/tests/types.sh:
- Fix a number of tests to report failures correctly.

Resolves: https://github.com/ksh93/ksh/issues/157
This commit is contained in:
Martijn Dekker 2021-03-06 03:56:52 +00:00
parent f8f2c4b608
commit 9f2389ed93
8 changed files with 60 additions and 19 deletions

View file

@ -1314,7 +1314,7 @@ retry1:
* a value; otherwise it always follows the code path for a set parameter, so is
* not subject to 'set -u', and may test as set even after 'unset -v IFS'.
*/
if(!(*id=='I' && strcmp(id,"IFS")==0 && nv_getval(sh_scoped(mp->shp,IFSNOD)) == NULL))
if(!(*id=='I' && strcmp(id,"IFS")==0 && nv_getval(sh_scoped(mp->shp,IFSNOD)) == NIL(char*)))
np = nv_open(id,mp->shp->var_tree,flag|NV_NOFAIL);
if(!np)
{
@ -1405,9 +1405,13 @@ retry1:
/*
* Check if the parameter is set or unset.
*/
if(np && (type==M_TREE || !c || !ap))
#if SHOPT_OPTIMIZE
if(np && type==M_BRACE && mp->shp->argaddr)
nv_optimize(np); /* needed before calling nv_isnull() */
#endif /* SHOPT_OPTIMIZE */
if(np && (type==M_BRACE ? !nv_isnull(np) : (type==M_TREE || !c || !ap)))
{
/* The parameter is set. */
/* Either the parameter is set, or it's a special type of expansion where 'unset' doesn't apply. */
char *savptr;
c = *((unsigned char*)stkptr(stkp,offset-1));
savptr = stkfreeze(stkp,0);
@ -1443,13 +1447,7 @@ retry1:
if(ap)
v = nv_arrayisset(np,ap)?(char*)"x":0;
else
{
#if SHOPT_OPTIMIZE
if(mp->shp->argaddr)
nv_optimize(np); /* avoid BUG_ISSETLOOP */
#endif /* SHOPT_OPTIMIZE */
v = nv_isnull(np)?0:(char*)"x";
}
}
else
v = nv_getval(np);