mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
Fix multiple bugs when using 'alias -p' to print aliases (#398)
This commit was originally intended to fix just one bug with shcomp's handling of 'alias -p', but while fixing that I found a large number of related issues in the alias command's -p, -t and -x options. The current patch provides bugfixes for all of the bugs listed below: 1) Listing aliases in a script with 'alias -p' or 'alias' broke shcomp's bytecode output: https://github.com/ksh93/ksh/issues/87#issuecomment-813819122 2) Listing individual aliases with the -p option doesn't work: $ alias foo=bar bar=foo $ alias foo foo=bar $ alias -p foo # No output 3) Listing specific tracked aliases with -pt does not display them in a reusable format, but rather adds another tracked alias: $ hash -r cat vi $ alias -pt vi # No output $ alias -pt rm $ alias -t cat=/usr/bin/cat rm=/usr/bin/rm vi=/usr/bin/vi 4) Listing all tracked aliases with -pt does not output them in a reusable format (the resulting command printed only creates a normal alias, which is different from a tracked alias): $ hash -r cat $ alias -pt alias cat=/usr/bin/cat # Expected 'alias -t cat' 5) Listing a non-existent alias with -p doesn't cause an error: $ unalias -a $ alias -p notanalias # No output $ echo $? 0 $ alias notanalias notanalias: alias not found $ echo $? 1 $ hash -r $ alias -pt notacommand # No output $ echo $? 0 6) Attempting to list 256 non-existent aliases results in exit status zero: $ unalias -a $ alias $(awk -v ORS= 'BEGIN { for(i=0;i<256;i++) print "x "; }') x: alias not found --cut error message-- $ echo $? 0 Changes: - typeset.c: Avoid printing anything while shcomp is compiling a script. This is needed because the alias command is run by shcomp to prevent parsing issues. - b_alias(): To avoid adding tracked aliases with -pt, set tdata.aflag to '+' so that setall() and other related functions only list tracked aliases. - b_alias(): Set tdata.pflag to 1 so that setall() and other functions recognize -p was passed. - print_value(): Add support for listing specific aliases with 'alias -p'. - setall(): To avoid any issues with zombie tracked aliases (see also the regression tests) ignore tracked alias nodes marked with the NV_NOALIAS attribute. This bit is set for tracked alias nodes by the nv_rehash() function. - setall(): For backward compatibility, continue incrementing the exit status for each invalid alias and tracked alias passed. This was already how alias behaved when listing aliases without -p, so using -p shouldn't cause a change in behavior: $ unalias -a $ alias foo bar foo: alias not found bar: alias not found $ echo $? 2 To fix bug 6, the exit status is set to one if an enforced 8-bit exit status would be zero. - print_namval(): Set the prefix to 'alias -t' so that listing tracked aliases with 'alias -pt' works correctly. - data/msg.c and include/name.h: Add an error message for when 'alias -pt' doesn't find a tracked alias. - tests/alias.sh: Add a ton of regression tests for the bugs fixed in this commit.
This commit is contained in:
parent
feeb62d15f
commit
f7213f03a2
8 changed files with 245 additions and 10 deletions
|
|
@ -132,7 +132,7 @@ int b_alias(int argc,register char *argv[],Shbltin_t *context)
|
|||
{
|
||||
register unsigned flag = NV_NOARRAY|NV_NOSCOPE|NV_ASSIGN;
|
||||
register Dt_t *troot;
|
||||
register int rflag=0, n;
|
||||
register int rflag=0, xflag=0, n;
|
||||
struct tdata tdata;
|
||||
NOT_USED(argc);
|
||||
memset((void*)&tdata,0,sizeof(tdata));
|
||||
|
|
@ -151,20 +151,26 @@ int b_alias(int argc,register char *argv[],Shbltin_t *context)
|
|||
{
|
||||
case 'p':
|
||||
tdata.prefix = argv[0];
|
||||
tdata.pflag = 1;
|
||||
break;
|
||||
case 't':
|
||||
flag |= NV_TAGGED;
|
||||
break;
|
||||
case 'x':
|
||||
/* obsolete, ignored */
|
||||
xflag = 1;
|
||||
break;
|
||||
case 'r':
|
||||
rflag=1;
|
||||
break;
|
||||
case ':':
|
||||
if(sh.shcomp)
|
||||
return(2); /* don't print usage info while shcomp is compiling */
|
||||
errormsg(SH_DICT,2, "%s", opt_info.arg);
|
||||
break;
|
||||
case '?':
|
||||
if(sh.shcomp)
|
||||
return(2);
|
||||
errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
|
||||
return(2);
|
||||
}
|
||||
|
|
@ -179,12 +185,17 @@ int b_alias(int argc,register char *argv[],Shbltin_t *context)
|
|||
if(flag&NV_TAGGED)
|
||||
{
|
||||
troot = sh_subtracktree(1); /* use hash table */
|
||||
tdata.aflag = '-'; /* make setall() treat 'hash' like 'alias -t' */
|
||||
if(tdata.pflag)
|
||||
tdata.aflag = '+'; /* for 'alias -pt', don't add anything to the hash table */
|
||||
else
|
||||
tdata.aflag = '-'; /* make setall() treat 'hash' like 'alias -t' */
|
||||
if(rflag) /* hash -r: clear hash table */
|
||||
nv_scan(troot,nv_rehash,(void*)0,NV_TAGGED,NV_TAGGED);
|
||||
}
|
||||
else if(argv[1] && tdata.sh->subshell && !tdata.sh->subshare)
|
||||
sh_subfork(); /* avoid affecting the parent shell's alias table */
|
||||
if(xflag && (flag&NV_TAGGED))
|
||||
return(0); /* do nothing for 'alias -tx' */
|
||||
return(setall(argv,flag,troot,&tdata));
|
||||
}
|
||||
|
||||
|
|
@ -597,6 +608,8 @@ static void print_value(Sfio_t *iop, Namval_t *np, struct tdata *tp)
|
|||
sfwrite(iop,"}\n",2);
|
||||
return;
|
||||
}
|
||||
if(tp->prefix && *tp->prefix=='a' && !nv_isattr(np,NV_TAGGED))
|
||||
sfprintf(iop,"%s ", tp->prefix);
|
||||
table = tp->sh->last_table;
|
||||
sfputr(iop,nv_name(np),aflag=='+'?'\n':'=');
|
||||
tp->sh->last_table = table;
|
||||
|
|
@ -736,8 +749,16 @@ static int setall(char **argv,register int flag,Dt_t *troot,struct tdata *tp
|
|||
continue;
|
||||
}
|
||||
np = nv_open(name,troot,nvflags|((nvflags&NV_ASSIGN)?0:NV_ARRAY)|((iarray|(nvflags&(NV_REF|NV_NOADD)==NV_REF))?NV_FARRAY:0));
|
||||
if(!np)
|
||||
if(!np || (troot==sh.track_tree && nv_isattr(np,NV_NOALIAS)))
|
||||
{
|
||||
if(troot==sh.alias_tree || troot==sh.track_tree)
|
||||
{
|
||||
if(!sh.shcomp)
|
||||
sfprintf(sfstderr,sh_translate(troot==sh.alias_tree ? e_noalias: e_notrackedalias),name);
|
||||
r++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(np->nvflag&NV_RDONLY && !tp->pflag
|
||||
&& (flag & ~(NV_ASSIGN|NV_RDONLY|NV_EXPORT))) /* allow readonly/export on readonly vars */
|
||||
{
|
||||
|
|
@ -775,7 +796,8 @@ static int setall(char **argv,register int flag,Dt_t *troot,struct tdata *tp
|
|||
{
|
||||
if(troot!=shp->var_tree && (nv_isnull(np) || !print_namval(sfstdout,np,0,tp)))
|
||||
{
|
||||
sfprintf(sfstderr,sh_translate(e_noalias),name);
|
||||
if(!sh.shcomp)
|
||||
sfprintf(sfstderr,sh_translate(e_noalias),name);
|
||||
r++;
|
||||
}
|
||||
if(!comvar && !iarray)
|
||||
|
|
@ -979,6 +1001,14 @@ static int setall(char **argv,register int flag,Dt_t *troot,struct tdata *tp
|
|||
print_all(sfstdout,troot,tp);
|
||||
sfsync(sfstdout);
|
||||
}
|
||||
/* This is to handle cases where more than 255 non-existent
|
||||
aliases were passed to the alias command. */
|
||||
if(r>255)
|
||||
{
|
||||
r &= SH_EXITMASK;
|
||||
if(r==0)
|
||||
r = 1; /* ensure the exit status is at least 1 */
|
||||
}
|
||||
return(r);
|
||||
}
|
||||
|
||||
|
|
@ -1404,6 +1434,8 @@ static int print_namval(Sfio_t *file,register Namval_t *np,register int flag, st
|
|||
flag = '\n';
|
||||
if(tp->noref && nv_isref(np))
|
||||
return(0);
|
||||
if(sh.shcomp)
|
||||
return(1); /* print nothing while shcomp is compiling */
|
||||
if(nv_isattr(np,NV_NOPRINT|NV_INTEGER)==NV_NOPRINT)
|
||||
{
|
||||
if(is_abuiltin(np))
|
||||
|
|
@ -1418,7 +1450,9 @@ static int print_namval(Sfio_t *file,register Namval_t *np,register int flag, st
|
|||
isfun = is_afunction(np);
|
||||
if(tp->prefix)
|
||||
{
|
||||
outname = (*tp->prefix=='t' && (!nv_isnull(np) || nv_isattr(np,NV_FLOAT|NV_RDONLY|NV_BINARY|NV_RJUST|NV_NOPRINT)));
|
||||
outname = (*tp->prefix=='t' && (!nv_isnull(np) || nv_isattr(np,NV_FLOAT|NV_RDONLY|NV_BINARY|NV_RJUST|NV_NOPRINT)));
|
||||
if(tp->scanroot==sh.track_tree && *tp->prefix=='a')
|
||||
tp->prefix = "alias -t";
|
||||
if(indent && (isfun || outname || *tp->prefix!='t'))
|
||||
{
|
||||
sfnputc(file,'\t',indent);
|
||||
|
|
@ -1427,7 +1461,7 @@ static int print_namval(Sfio_t *file,register Namval_t *np,register int flag, st
|
|||
if(!isfun)
|
||||
{
|
||||
if(*tp->prefix=='t')
|
||||
nv_attribute(np,tp->outfile,tp->prefix,tp->aflag);
|
||||
nv_attribute(np,tp->outfile,tp->prefix,tp->aflag);
|
||||
else
|
||||
sfputr(file,tp->prefix,' ');
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue