mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
Fix the output of typeset -p
for two dimensional indexed arrays (#454)
In ksh93v- 2012-10-04 the following bugfix is noted in the changelog (this fix was most likely part of ksh93v- 2012-09-27, although that version is not archived anywhere): 12-09-21 A bug in which the output of a two dimensional sparse indexed array would cause the second subscript be treated as an associative array when read back in has been fixed. Elements that are sparse indexed arrays now are prefixed type "typeset -a". Below is a before and after of this change: # Before $ typeset -a foo[1][2]=bar $ typeset -p foo typeset -a foo=([1]=([2]=bar) ) # After $ typeset -a foo[1][2]=bar $ typeset -p foo typeset -a foo=(typeset -a [1]=([2]=bar) ) src/cmd/ksh93/sh/*.c: - Backport changes from ksh93v- to print 'typeset -a' before sparse indexed arrays and properly handle 'typeset -a' in reinput commands from 'typeset -p'. src/cmd/ksh93/tests: - Add two regression tests to arrays.sh for this change. - Update the existing regression tests for compatibility with the new printed typeset output.
This commit is contained in:
parent
e6d0187dd8
commit
787058bdbf
13 changed files with 80 additions and 16 deletions
5
NEWS
5
NEWS
|
@ -14,6 +14,11 @@ Any uppercase BUG_* names are modernish shell bug IDs.
|
|||
an incompletely defined 'foo_t' built-in comamnd that will crash the shell
|
||||
when used. Instead, it is now silently ignored for backwards compatibility.
|
||||
|
||||
- A bug in which the output of a two dimensional sparse indexed array would
|
||||
cause the second subscript to be treated as an associative array when read
|
||||
back in has been fixed. Elements that are sparse indexed arrays are now
|
||||
prefixed with "typeset -a".
|
||||
|
||||
2022-02-05:
|
||||
|
||||
- Fixed: for indexed arrays, given an unset array member a[i] with i > 0,
|
||||
|
|
|
@ -120,6 +120,7 @@ struct argnod
|
|||
#define ARG_QUOTED 0x20 /* word contained quote characters */
|
||||
#define ARG_MESSAGE 0x40 /* contains international string */
|
||||
#define ARG_APPEND 0x80 /* for += assignment */
|
||||
#define ARG_ARRAY 0x2 /* for typeset -a */
|
||||
/* The following can be passed as options to sh_macexpand() */
|
||||
#define ARG_ARITH 0x100 /* arithmetic expansion */
|
||||
#define ARG_OPTIMIZE 0x200 /* try to optimize */
|
||||
|
|
|
@ -90,6 +90,7 @@ typedef struct _shlex_
|
|||
char noreserv; /* reserved works not legal */
|
||||
int inlineno; /* saved value of sh.inlineno */
|
||||
int firstline; /* saved value of sh.st.firstline */
|
||||
int assignlevel; /* nesting level for assignment */
|
||||
#if SHOPT_KIA
|
||||
Sfio_t *kiafile; /* kia output file */
|
||||
Sfio_t *kiatmp; /* kia reference file */
|
||||
|
|
|
@ -308,13 +308,15 @@ void nv_setlist(register struct argnod *arg,register int flags, Namval_t *typ)
|
|||
else
|
||||
{
|
||||
stakseek(0);
|
||||
if(*arg->argval==0 && arg->argchn.ap && !(arg->argflag&~(ARG_APPEND|ARG_QUOTED|ARG_MESSAGE)))
|
||||
if(*arg->argval==0 && arg->argchn.ap && !(arg->argflag&~(ARG_APPEND|ARG_QUOTED|ARG_MESSAGE|ARG_ARRAY)))
|
||||
{
|
||||
int flag = (NV_VARNAME|NV_ARRAY|NV_ASSIGN);
|
||||
int sub=0;
|
||||
struct fornod *fp=(struct fornod*)arg->argchn.ap;
|
||||
register Shnode_t *tp=fp->fortre;
|
||||
flag |= (flags&(NV_NOSCOPE|NV_STATIC|NV_FARRAY));
|
||||
if(arg->argflag&ARG_ARRAY)
|
||||
array |= NV_IARRAY;
|
||||
if(arg->argflag&ARG_QUOTED)
|
||||
cp = sh_mactrim(fp->fornam,-1);
|
||||
else
|
||||
|
|
|
@ -587,6 +587,9 @@ void nv_outnode(Namval_t *np, Sfio_t* out, int indent, int special)
|
|||
tabs=0;
|
||||
if(associative||special)
|
||||
{
|
||||
Namarr_t *aq;
|
||||
if(mp && (aq=nv_arrayptr(mp)) && !aq->fun && array_elem(aq) < nv_aimax(mp)+1)
|
||||
sfwrite(out,"typeset -a ",11);
|
||||
if(!(fmtq = nv_getsub(np)))
|
||||
break;
|
||||
sfprintf(out,"[%s]",sh_fmtq(fmtq));
|
||||
|
|
|
@ -377,6 +377,7 @@ void *sh_parse(Sfio_t *iop, int flag)
|
|||
return((void*)sh_trestore(iop));
|
||||
fcsave(&sav_input);
|
||||
sh.st.staklist = 0;
|
||||
lexp->assignlevel = 0;
|
||||
lexp->noreserv = 0;
|
||||
lexp->heredoc = 0;
|
||||
lexp->inlineno = sh.inlineno;
|
||||
|
@ -967,6 +968,30 @@ static Shnode_t *funct(Lex_t *lexp)
|
|||
return(t);
|
||||
}
|
||||
|
||||
static int check_array(Lex_t *lexp)
|
||||
{
|
||||
int n,c;
|
||||
if(lexp->token==0 && strcmp(lexp->arg->argval, SYSTYPESET->nvname)==0)
|
||||
{
|
||||
while((c=fcgetc(n))==' ' || c=='\t');
|
||||
if(c=='-')
|
||||
{
|
||||
if(fcgetc(n)=='a')
|
||||
{
|
||||
lexp->assignok = SH_ASSIGN;
|
||||
lexp->noreserv = 1;
|
||||
sh_lex(lexp);
|
||||
return(1);
|
||||
}
|
||||
else
|
||||
fcseek(-2);
|
||||
}
|
||||
else
|
||||
fcseek(-1);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compound assignment
|
||||
*/
|
||||
|
@ -978,6 +1003,7 @@ static struct argnod *assign(Lex_t *lexp, register struct argnod *ap, int type)
|
|||
Stk_t *stkp = sh.stk;
|
||||
int array=0, index=0;
|
||||
Namval_t *np;
|
||||
lexp->assignlevel++;
|
||||
n = strlen(ap->argval)-1;
|
||||
if(ap->argval[n]!='=')
|
||||
sh_syntax(lexp);
|
||||
|
@ -1002,14 +1028,14 @@ static struct argnod *assign(Lex_t *lexp, register struct argnod *ap, int type)
|
|||
ap->argflag &= ARG_QUOTED;
|
||||
ap->argflag |= array;
|
||||
lexp->assignok = SH_ASSIGN;
|
||||
if(type==NV_ARRAY)
|
||||
if(type&NV_ARRAY)
|
||||
{
|
||||
lexp->noreserv = 1;
|
||||
lexp->assignok = 0;
|
||||
}
|
||||
else
|
||||
lexp->aliasok = 2;
|
||||
array= (type==NV_ARRAY)?SH_ARRAY:0;
|
||||
array= (type&NV_ARRAY)?SH_ARRAY:0;
|
||||
if((n=skipnl(lexp,0))==RPAREN || n==LPAREN)
|
||||
{
|
||||
struct argnod *ar,*aq,**settail;
|
||||
|
@ -1148,6 +1174,7 @@ static struct argnod *assign(Lex_t *lexp, register struct argnod *ap, int type)
|
|||
}
|
||||
*tp = (Shnode_t*)ac;
|
||||
lexp->assignok = 0;
|
||||
lexp->assignlevel--;
|
||||
return(ap);
|
||||
}
|
||||
|
||||
|
@ -1432,7 +1459,9 @@ static Shnode_t *simple(Lex_t *lexp,int flag, struct ionod *io)
|
|||
Stk_t *stkp = sh.stk;
|
||||
struct argnod **argtail;
|
||||
struct argnod **settail;
|
||||
int cmdarg=0;
|
||||
int cmdarg = 0;
|
||||
int type = 0;
|
||||
int was_assign = 0;
|
||||
int argno = 0;
|
||||
int assignment = 0;
|
||||
int key_on = (!(flag&SH_NOIO) && sh_isoption(SH_KEYWORD));
|
||||
|
@ -1452,8 +1481,11 @@ static Shnode_t *simple(Lex_t *lexp,int flag, struct ionod *io)
|
|||
t->comnamq = 0;
|
||||
t->comstate = 0;
|
||||
settail = &(t->comset);
|
||||
if(lexp->assignlevel && (flag&SH_ARRAY) && check_array(lexp))
|
||||
type |= NV_ARRAY;
|
||||
while(lexp->token==0)
|
||||
{
|
||||
was_assign = 0;
|
||||
argp = lexp->arg;
|
||||
if(*argp->argval==LBRACE && (flag&SH_FUNDEF) && argp->argval[1]==0)
|
||||
{
|
||||
|
@ -1531,6 +1563,8 @@ static Shnode_t *simple(Lex_t *lexp,int flag, struct ionod *io)
|
|||
}
|
||||
retry:
|
||||
tok = sh_lex(lexp);
|
||||
if(was_assign && check_array(lexp))
|
||||
type = NV_ARRAY;
|
||||
if(tok==LABLSYM && (flag&SH_ASSIGN))
|
||||
lexp->token = tok = 0;
|
||||
if((tok==IPROCSYM || tok==OPROCSYM))
|
||||
|
@ -1546,7 +1580,6 @@ static Shnode_t *simple(Lex_t *lexp,int flag, struct ionod *io)
|
|||
if(argp->argflag&ARG_ASSIGN)
|
||||
{
|
||||
int intypeset = lexp->intypeset;
|
||||
int type = 0;
|
||||
lexp->intypeset = 0;
|
||||
if(t->comnamp == SYSCOMPOUND)
|
||||
type = NV_COMVAR;
|
||||
|
@ -1558,18 +1591,21 @@ static Shnode_t *simple(Lex_t *lexp,int flag, struct ionod *io)
|
|||
if(*ap->argval!='-')
|
||||
break;
|
||||
if(strchr(ap->argval,'T'))
|
||||
type = NV_TYPE;
|
||||
type |= NV_TYPE;
|
||||
else if(strchr(ap->argval,'a'))
|
||||
type = NV_ARRAY;
|
||||
type |= NV_ARRAY;
|
||||
else if(strchr(ap->argval,'C'))
|
||||
type = NV_COMVAR;
|
||||
type |= NV_COMVAR;
|
||||
else
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
argp = assign(lexp,argp,type);
|
||||
if(type==NV_ARRAY)
|
||||
argp->argflag |= ARG_ARRAY;
|
||||
lexp->intypeset = intypeset;
|
||||
if(lexp->assignlevel)
|
||||
was_assign = 1;
|
||||
if(associative)
|
||||
lexp->assignok |= SH_ASSIGN;
|
||||
goto retry;
|
||||
|
|
|
@ -160,7 +160,7 @@ static int p_arg(register const struct argnod *arg)
|
|||
struct fornod *fp;
|
||||
while(arg)
|
||||
{
|
||||
if((n = strlen(arg->argval)) || (arg->argflag&~(ARG_APPEND|ARG_MESSAGE|ARG_QUOTED)))
|
||||
if((n = strlen(arg->argval)) || (arg->argflag&~(ARG_APPEND|ARG_MESSAGE|ARG_QUOTED|ARG_ARRAY)))
|
||||
fp=0;
|
||||
else
|
||||
{
|
||||
|
|
|
@ -195,7 +195,7 @@ static struct argnod *r_arg(void)
|
|||
ap = (struct argnod*)stkfreeze(stkp,0);
|
||||
if(*ap->argval==0 && (ap->argflag&ARG_EXP))
|
||||
ap->argchn.ap = (struct argnod*)r_tree();
|
||||
else if(*ap->argval==0 && (ap->argflag&~(ARG_APPEND|ARG_MESSAGE|ARG_QUOTED))==0)
|
||||
else if(*ap->argval==0 && (ap->argflag&~(ARG_APPEND|ARG_MESSAGE|ARG_QUOTED|ARG_ARRAY))==0)
|
||||
{
|
||||
struct fornod *fp = (struct fornod*)getnode(fornod);
|
||||
fp->fortyp = sfgetu(infile);
|
||||
|
|
|
@ -803,5 +803,21 @@ got=$(set +x; redirect 2>&1; foo[42]=''; : ${foo[42]:?})
|
|||
[[ $got == *"$exp" ]] || err_exit '${array[index]:?error} does not throw error' \
|
||||
"(expected match of *$(printf %q "$exp"), got $(printf %q "$got"))"
|
||||
|
||||
# ======
|
||||
# A multidimensional indexed array should be printed correctly by
|
||||
# 'typeset -p'. Additionally, the printed command must produce the
|
||||
# same result when reinput to the shell.
|
||||
unset foo
|
||||
typeset -a foo[1][2]=bar
|
||||
exp='typeset -a foo=(typeset -a [1]=([2]=bar) )'
|
||||
got=$(typeset -p foo)
|
||||
[[ $exp == "$got" ]] || err_exit "Multidimensional indexed arrays are not printed correctly with 'typeset -p'" \
|
||||
"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
|
||||
unset foo
|
||||
typeset -a foo=(typeset -a [1]=([2]=bar) )
|
||||
got=$(typeset -p foo)
|
||||
[[ $exp == "$got" ]] || err_exit "Output from 'typeset -p' for indexed array cannot be used for reinput" \
|
||||
"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
|
||||
|
||||
# ======
|
||||
exit $((Errors<125?Errors:125))
|
||||
|
|
|
@ -159,7 +159,7 @@ done
|
|||
|
||||
$SHELL 2> /dev/null -c 'compound c;float -a c.ar;(( c.ar[2][3][3] = 5))' || 'multidimensional arrays in arithmetic expressions not working'
|
||||
|
||||
expected='typeset -a -l -E c.ar=([2]=([3]=([3]=5) ) )'
|
||||
expected='typeset -a -l -E c.ar=(typeset -a [2]=(typeset -a [3]=([3]=5) ) )'
|
||||
unset c
|
||||
float c.ar
|
||||
c.ar[2][3][3]=5
|
||||
|
|
|
@ -668,7 +668,7 @@ compound -a c.board
|
|||
for ((i=2; i < 4; i++))
|
||||
do c.board[1][$i]=(foo=bar)
|
||||
done
|
||||
exp=$'(\n\ttypeset -C -a board=(\n\t\t[1]=(\n\t\t\t[2]=(\n\t\t\t\tfoo=bar\n\t\t\t)\n\t\t\t[3]=(\n\t\t\t\tfoo=bar\n\t\t\t)\n\t\t)\n\t)\n)'
|
||||
exp=$'(\n\ttypeset -C -a board=(\n\t\ttypeset -a [1]=(\n\t\t\t[2]=(\n\t\t\t\tfoo=bar\n\t\t\t)\n\t\t\t[3]=(\n\t\t\t\tfoo=bar\n\t\t\t)\n\t\t)\n\t)\n)'
|
||||
[[ "$(print -v c)" == "$exp" ]] || err_exit 'compound variable assignment to two dimensional array not working'
|
||||
|
||||
unset zz
|
||||
|
|
|
@ -593,7 +593,7 @@ function read_c
|
|||
read -C v
|
||||
}
|
||||
print "( typeset -i x=36 ) " | read_c ar[5][9][2]
|
||||
exp=$'(\n\t[5]=(\n\t\t[9]=(\n\t\t\t[2]=(\n\t\t\t\ttypeset -i x=36\n\t\t\t)\n\t\t)\n\t)\n)'
|
||||
exp=$'(\n\ttypeset -a [5]=(\n\t\ttypeset -a [9]=(\n\t\t\t[2]=(\n\t\t\t\ttypeset -i x=36\n\t\t\t)\n\t\t)\n\t)\n)'
|
||||
[[ $(print -v ar) == "$exp" ]] || err_exit 'read into nameref of global array instance from within a function fails'
|
||||
|
||||
function read_c
|
||||
|
@ -606,7 +606,7 @@ function main
|
|||
compound -a ar
|
||||
nameref nar=ar
|
||||
print "( typeset -i x=36 ) " | read_c nar[5][9][2]
|
||||
exp=$'(\n\t[5]=(\n\t\t[9]=(\n\t\t\t[2]=(\n\t\t\t\ttypeset -i x=36\n\t\t\t)\n\t\t)\n\t)\n)'
|
||||
exp=$'(\n\ttypeset -a [5]=(\n\t\ttypeset -a [9]=(\n\t\t\t[2]=(\n\t\t\t\ttypeset -i x=36\n\t\t\t)\n\t\t)\n\t)\n)'
|
||||
[[ $(print -v nar) == "$exp" ]] || err_exit 'read from a nameref variable from calling scope fails'
|
||||
}
|
||||
main
|
||||
|
|
|
@ -108,7 +108,7 @@ function m
|
|||
x_t c.x[4][5][8].field
|
||||
x_t x
|
||||
typeset -m c.x[4][6][9].field=x
|
||||
exp=$'(\n\ttypeset -C -a x=(\n\t\t[4]=(\n\t\t\t[5]=(\n\t\t\t\t[8]=(\n\t\t\t\t\tx_t field=(\n\t\t\t\t\t\thello=world\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t)\n\t\t\t[6]=(\n\t\t\t\t[9]=(\n\t\t\t\t\tx_t field=(\n\t\t\t\t\t\thello=world\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t)\n\t\t)\n\t)\n)'
|
||||
exp=$'(\n\ttypeset -C -a x=(\n\t\ttypeset -a [4]=(\n\t\t\ttypeset -a [5]=(\n\t\t\t\t[8]=(\n\t\t\t\t\tx_t field=(\n\t\t\t\t\t\thello=world\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t)\n\t\t\ttypeset -a [6]=(\n\t\t\t\t[9]=(\n\t\t\t\t\tx_t field=(\n\t\t\t\t\t\thello=world\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t)\n\t\t)\n\t)\n)'
|
||||
[[ $(print -v c) == "$exp" ]] || err_exit "typeset -m c.x[4][6][9].field=x where x is a type is not working"
|
||||
}
|
||||
m
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue