diff --git a/NEWS b/NEWS index 569bcdab4..487c048eb 100644 --- a/NEWS +++ b/NEWS @@ -23,6 +23,8 @@ Any uppercase BUG_* names are modernish shell bug IDs. of declaration built-ins. This reverts a change introduced on 2020-09-11. [*] https://austingroupbugs.net/view.php?id=1393 +- Fixed arithmetic assignment operations for multidimensional indexed arrays + 2021-04-30: - The emacs 'ESC .' (M-.) and vi '_' commands now take shell quoting into diff --git a/src/cmd/ksh93/include/streval.h b/src/cmd/ksh93/include/streval.h index ea64a0c8b..a62cc6b9f 100644 --- a/src/cmd/ksh93/include/streval.h +++ b/src/cmd/ksh93/include/streval.h @@ -76,6 +76,7 @@ struct lval const char *expr; const void *ptr; int nosub; + char *sub; short flag; short nargs; short emode; diff --git a/src/cmd/ksh93/sh/arith.c b/src/cmd/ksh93/sh/arith.c index 47de20723..603876c06 100644 --- a/src/cmd/ksh93/sh/arith.c +++ b/src/cmd/ksh93/sh/arith.c @@ -233,8 +233,17 @@ static Sfdouble_t arith(const char **ptr, struct lval *lvalue, int type, Sfdoubl { case ASSIGN: { - register Namval_t *np = (Namval_t*)(lvalue->value); - np = scope(np,lvalue,1); + register Namval_t *np; + if (lvalue->nosub > 0 && lvalue->sub) /* indexed array ARITH_ASSIGNOP */ + { + np = (Namval_t*)lvalue->sub; /* use saved subscript reference instead of last worked value */ + nv_putsub(np, NIL(char*), lvalue->nosub-1); + } + else + { + np = (Namval_t*)lvalue->value; + np = scope(np, lvalue, 1); + } nv_putval(np, (char*)&n, NV_LDOUBLE); if(lvalue->eflag) lvalue->ptr = (void*)nv_hasdisc(np,&ENUM_disc); @@ -494,7 +503,10 @@ static Sfdouble_t arith(const char **ptr, struct lval *lvalue, int type, Sfdoubl else if(nv_isattr(np,NV_DOUBLE)==NV_DOUBLE) lvalue->isfloat=1; if((lvalue->emode&ARITH_ASSIGNOP) && nv_isarray(np)) - lvalue->nosub = nv_aindex(np)+1; + { + lvalue->nosub = nv_aindex(np)+1; /* subscript number of array */ + lvalue->sub = (char*)np; /* store subscript reference for upcoming iteration of ASSIGN */ + } return(r); } diff --git a/src/cmd/ksh93/sh/streval.c b/src/cmd/ksh93/sh/streval.c index a115ee9f3..98e449ec9 100644 --- a/src/cmd/ksh93/sh/streval.c +++ b/src/cmd/ksh93/sh/streval.c @@ -172,6 +172,7 @@ Sfdouble_t arith_exec(Arith_t *ep) node.elen = ep->elen; node.value = 0; node.nosub = 0; + node.sub = 0; node.ptr = 0; node.eflag = 0; if(shp->arithrecursion++ >= MAXLEVEL) diff --git a/src/cmd/ksh93/tests/arrays2.sh b/src/cmd/ksh93/tests/arrays2.sh index 5771a1d5c..2f7fda3bd 100755 --- a/src/cmd/ksh93/tests/arrays2.sh +++ b/src/cmd/ksh93/tests/arrays2.sh @@ -240,5 +240,24 @@ foo EOF $SHELL "$multiarray_unset" > /dev/null || err_exit 'Multidimensional arrays with an unset method crash ksh' +# ====== +# Multidimensional indexed array arithmetic assignment operation tests +ini() { unset arr; typeset -a arr=((10 20) 6 8); } +[[ $( ini; ((arr[0][0]+=1)); typeset -p arr) == 'typeset -a arr=((11 20) 6 8)' ]] || err_exit 'ASSIGNOP: arr[0][0]+=1 failed.' +[[ $( ini; ((arr[0][1]+=1)); typeset -p arr) == 'typeset -a arr=((10 21) 6 8)' ]] || err_exit 'ASSIGNOP: arr[0][1]+=1 failed.' +[[ $( ini; ((arr[0][2]+=1)); typeset -p arr) == 'typeset -a arr=((10 20 1) 6 8)' ]] || err_exit 'ASSIGNOP: arr[0][2]+=1 failed.' +[[ $( ini; ((arr[0][1]+=arr[1])); typeset -p arr) == 'typeset -a arr=((10 26) 6 8)' ]] || err_exit 'ASSIGNOP: arr[0][1]+=arr[1] failed.' +[[ $( ini; ((arr[0][2]+=arr[1])); typeset -p arr) == 'typeset -a arr=((10 20 6) 6 8)' ]] || err_exit 'ASSIGNOP: arr[0][2]+=arr[1] failed.' +[[ $( ini; ((arr[1]+=1)); typeset -p arr) == 'typeset -a arr=((10 20) 7 8)' ]] || err_exit 'ASSIGNOP: arr[1]+=1 failed.' +[[ $( ini; ((arr[2]+=1)); typeset -p arr) == 'typeset -a arr=((10 20) 6 9)' ]] || err_exit 'ASSIGNOP: arr[2]+=1 failed.' +[[ $( ini; ((arr[3]+=1)); typeset -p arr) == 'typeset -a arr=((10 20) 6 8 1)' ]] || err_exit 'ASSIGNOP: arr[3]+=1 failed.' +[[ $( ini; ((arr[1]+=arr[0][0])); typeset -p arr) == 'typeset -a arr=((10 20) 16 8)' ]] || err_exit 'ASSIGNOP: arr[1]+=arr[0][0] failed.' +[[ $( ini; ((arr[1]+=arr[0][1])); typeset -p arr) == 'typeset -a arr=((10 20) 26 8)' ]] || err_exit 'ASSIGNOP: arr[1]+=arr[0][1] failed.' +[[ $( ini; ((arr[2]+=arr[0][0])); typeset -p arr) == 'typeset -a arr=((10 20) 6 18)' ]] || err_exit 'ASSIGNOP: arr[2]+=arr[0][0] failed.' +[[ $( ini; ((arr[2]+=arr[0][1])); typeset -p arr) == 'typeset -a arr=((10 20) 6 28)' ]] || err_exit 'ASSIGNOP: arr[2]+=arr[0][1] failed.' +[[ $( ini; ((arr[3]+=arr[0][1])); typeset -p arr) == 'typeset -a arr=((10 20) 6 8 20)' ]] || err_exit 'ASSIGNOP: arr[2]+=arr[0][1] failed.' +unset arr +unset -f ini + # ====== exit $((Errors<125?Errors:125))