1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-02-13 19:52:20 +00:00

Refactor new b_hash(); better hash table clear (re: d8428a83)

The b_hash() function duplicated much of its code from b_alias(),
while b_alias() retained some code to support being called as
'hash'. There is no reason why 'hash' and 'alias' can't be handled
with a single function, as is the case several other builtins. Note
that option parsing can easily be made dependent on the name the
command was invoked with (in this case, argv[0]=='h').

The new hash builtin's -r option cleared the hash table by
assigning to PATH its existing value, triggering its associated
discipline function (put_restricted() in init.c) which then
actually cleared the hash table. That's a bit of a hack. It's nicer
if we can just do that directly. This requires taking a static
handler function rehash() from init.c, which invalidates one hash
table entry, and making it available to the builtin.

src/cmd/ksh93/bltins/typeset.c,
src/cmd/ksh93/include/builtins.h,
src/cmd/ksh93/include/nval.h,
src/cmd/ksh93/sh/init.c,
src/cmd/ksh93/sh/name.c:
- Merge b_hash() into b_alias().
- The -x option was still uselessly setting the NV_EXPORT flag.
  Exported aliases were in ksh88 but were removed in ksh93.
- Rename rehash() handler function from init.c to nv_rehash
  (avoiding a possible conflict with another rehash() in cd_pwd.c)
  and move it to name.c just above nv_scan(), which it's meant to
  be used with. Make it an extern so typeset.c can use it.
- b_alias(): Replace the PATH assignment by an nv_scan() call to
  clear the hash table directly using the nv_rehash() handler.

src/cmd/ksh93/data/builtins.c:
- POSIX compliance fix: Remove BLT_SPC (special builtin) flag from
  "alias" definition. 'alias' is specified as a regular builtin.
- sh_optalias[]: Fix uninformative -t option documentation.
- sh_opthash[]: Edit for conciseness and clarity.

src/cmd/ksh93/sh.1:
- Edit the 'alias -t' and 'hash' documentation.
- Remove the -- prefix from the 'alias' entry, which indicated that
  it was supposed to be a declaration builtin like 'typeset', with
  assignment-arguments expanding tildes and not being subject to
  field splitting. However, my testing shows that 'alias' has never
  actually behaved that way on ksh93. Even adding the BLT_DCL flag
  in data/builtins.c doesn't seem to change that.

(cherry picked from commit afa68dca5c786daa13213973e8b0f9bf3a1dadf6)
This commit is contained in:
Martijn Dekker 2020-06-11 05:23:38 +02:00
parent 74b4162178
commit 80d9ae2b1c
8 changed files with 68 additions and 98 deletions

View file

@ -133,56 +133,20 @@ int b_readonly(int argc,char *argv[],Shbltin_t *context)
return(setall(argv,flag,tdata.sh->var_tree, &tdata)); return(setall(argv,flag,tdata.sh->var_tree, &tdata));
} }
int b_hash(int argc,char *argv[],Shbltin_t *context) /*
{ * 'alias' and 'hash' builtins
register unsigned flag = NV_NOARRAY | NV_NOSCOPE | NV_ASSIGN | NV_TAGGED; */
register Dt_t *troot; #if 0
register int rflag=0, n; /* for the dictionary generator */
struct tdata tdata; int b_hash(int argc,register char *argv[],Shbltin_t *context){}
NOT_USED(argc); #endif
memset((void *)&tdata, 0, sizeof(tdata));
tdata.sh = context->shp;
troot = tdata.sh->alias_tree;
/* The hash utility should not be recognized as the alias builtin */
tdata.aflag = '-';
while((n = optget(argv,sh_opthash))) switch(n)
{
case 'r':
rflag = 1;
break;
case ':':
error(2,"%s",opt_info.arg);
break;
case '?':
error(ERROR_usage(0),"%s",opt_info.arg);
return 2;
}
if (error_info.errors)
errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NULL));
argv += (opt_info.index-1);
/* Handle -r */
if (rflag)
{
Namval_t *np = nv_search((char *)PATHNOD, tdata.sh->var_tree, HASH_BUCKET);
nv_putval(np, nv_getval(np), NV_RDONLY);
}
troot = tdata.sh->track_tree;
/* We must fork in subshells to avoid polluting the parent shell's hash table. */
if(tdata.sh->subshell && !tdata.sh->subshare)
sh_subfork();
return setall(argv, flag, troot, &tdata);
}
int b_alias(int argc,register char *argv[],Shbltin_t *context) int b_alias(int argc,register char *argv[],Shbltin_t *context)
{ {
register unsigned flag = NV_NOARRAY|NV_NOSCOPE|NV_ASSIGN; register unsigned flag = NV_NOARRAY|NV_NOSCOPE|NV_ASSIGN;
register Dt_t *troot; register Dt_t *troot;
register int n; register int rflag=0, n;
struct tdata tdata; struct tdata tdata;
Namval_t *np;
NOT_USED(argc); NOT_USED(argc);
memset((void*)&tdata,0,sizeof(tdata)); memset((void*)&tdata,0,sizeof(tdata));
tdata.sh = context->shp; tdata.sh = context->shp;
@ -196,7 +160,7 @@ int b_alias(int argc,register char *argv[],Shbltin_t *context)
*opt_info.option = 0; *opt_info.option = 0;
tdata.argnum = 0; tdata.argnum = 0;
tdata.aflag = *argv[1]; tdata.aflag = *argv[1];
while((n = optget(argv,sh_optalias))) switch(n) while((n = optget(argv, *argv[0]=='h' ? sh_opthash : sh_optalias))) switch(n)
{ {
case 'p': case 'p':
tdata.prefix = argv[0]; tdata.prefix = argv[0];
@ -205,7 +169,10 @@ int b_alias(int argc,register char *argv[],Shbltin_t *context)
flag |= NV_TAGGED; flag |= NV_TAGGED;
break; break;
case 'x': case 'x':
flag |= NV_EXPORT; /* obsolete, ignored */
break;
case 'r':
rflag=1;
break; break;
case ':': case ':':
errormsg(SH_DICT,2, "%s", opt_info.arg); errormsg(SH_DICT,2, "%s", opt_info.arg);
@ -217,11 +184,18 @@ int b_alias(int argc,register char *argv[],Shbltin_t *context)
if(error_info.errors) if(error_info.errors)
errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*))); errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*)));
argv += (opt_info.index-1); argv += (opt_info.index-1);
if(flag&NV_TAGGED)
troot = tdata.sh->track_tree;
} }
if(context->shp->subshell && !context->shp->subshare) /* fork a virtual subshell to avoid affecting parent shell's hash/alias table */
if((argv[1] || rflag) && tdata.sh->subshell && !tdata.sh->subshare)
sh_subfork(); sh_subfork();
/* 'alias -t', 'hash' */
if(flag&NV_TAGGED)
{
troot = tdata.sh->track_tree; /* use hash table */
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);
}
return(setall(argv,flag,troot,&tdata)); return(setall(argv,flag,troot,&tdata));
} }

View file

@ -78,8 +78,8 @@ const struct shtable3 shtab_builtins[] =
#if _bin_newgrp || _usr_bin_newgrp #if _bin_newgrp || _usr_bin_newgrp
"newgrp", NV_BLTIN|BLT_ENV|BLT_SPC, Bltin(login), "newgrp", NV_BLTIN|BLT_ENV|BLT_SPC, Bltin(login),
#endif /* _bin_newgrp || _usr_bin_newgrp */ #endif /* _bin_newgrp || _usr_bin_newgrp */
"alias", NV_BLTIN|BLT_SPC, bltin(alias), "alias", NV_BLTIN, bltin(alias),
"hash", NV_BLTIN, bltin(hash), "hash", NV_BLTIN, bltin(alias),
"enum", NV_BLTIN|BLT_ENV|BLT_SPC|BLT_DCL,bltin(enum), "enum", NV_BLTIN|BLT_ENV|BLT_SPC|BLT_DCL,bltin(enum),
"eval", NV_BLTIN|BLT_ENV|BLT_SPC|BLT_EXIT,bltin(eval), "eval", NV_BLTIN|BLT_ENV|BLT_SPC|BLT_EXIT,bltin(eval),
"exit", NV_BLTIN|BLT_ENV|BLT_SPC, bltin(return), "exit", NV_BLTIN|BLT_ENV|BLT_SPC, bltin(return),
@ -339,7 +339,7 @@ USAGE_LICENSE
const char sh_optalarm[] = "r [varname seconds]"; const char sh_optalarm[] = "r [varname seconds]";
const char sh_optalias[] = const char sh_optalias[] =
"[-1c?\n@(#)$Id: alias (AT&T Research) 1999-07-07 $\n]" "[-1c?\n@(#)$Id: alias (AT&T Research/ksh community) 2020-06-10 $\n]"
USAGE_LICENSE USAGE_LICENSE
"[+NAME?alias - define or display aliases]" "[+NAME?alias - define or display aliases]"
"[+DESCRIPTION?\balias\b creates or redefines alias definitions " "[+DESCRIPTION?\balias\b creates or redefines alias definitions "
@ -363,10 +363,9 @@ USAGE_LICENSE
"environment. It does not effect scripts run by this shell.]" "environment. It does not effect scripts run by this shell.]"
"[p?Causes the output to be in the form of alias commands that can be used " "[p?Causes the output to be in the form of alias commands that can be used "
"as input to the shell to recreate the current aliases.]" "as input to the shell to recreate the current aliases.]"
"[t?Used for tracked aliases. These are aliases that connect a " "[t?Each \aname\a is looked up as a command in \b$PATH\b and its path is "
"command name to the pathname of the command and are reset " "added to the hash table as a 'tracked alias'. If no \aname\a is "
"when the \bPATH\b variable is unset. The tracked aliases feature is " "given, this prints the hash table. See \bhash(1)\b.]"
"now obsolete.]"
"[x?Ignored, this option is obsolete.]" "[x?Ignored, this option is obsolete.]"
"\n" "\n"
"\n[name[=value]...]\n" "\n[name[=value]...]\n"
@ -932,13 +931,12 @@ _JOB_
const char sh_opthash[] = const char sh_opthash[] =
"[-1c?\n@(#)$Id: hash (ksh community) 2020-06-10 $\n]" "[-1c?\n@(#)$Id: hash (ksh community) 2020-06-10 $\n]"
"[+NAME?hash - display the locations of recently used programs]" "[+NAME?hash - display the locations of recently used programs]"
"[+DESCRIPTION?The \bhash\b utility is used to display or modify " "[+DESCRIPTION?\bhash\b displays or modifies the hash table with the "
"the hash table, which contains the locations of " "locations of recently used programs. If given no arguments, it lists "
"recently used programs. When \bhash\b is given no arguments, " "all command/path associations (a.k.a. 'tracked aliases') in the hash "
"it will list all commands in the hash table. If \autility\a is " "table. Otherwise, \bhash\b performs a \bPATH\b search for each "
"supplied, \bhash\b will add that utility to the hash table.]" "\autility\a supplied and adds the result to the hash table.]"
"[r?This option will empty the hash table. The effect of " "[r?Empty the hash table. This can also be achieved by resetting \bPATH\b.]"
"this flag can also be achieved by resetting the value of \bPATH\b.]"
"\n" "\n"
"\n[utility...]\n" "\n[utility...]\n"
"\n" "\n"
@ -946,7 +944,6 @@ const char sh_opthash[] =
"[+0?Successful completion.]" "[+0?Successful completion.]"
"[+>0?An error occured.]" "[+>0?An error occured.]"
"}" "}"
"[+SEE ALSO?\bsh\b(1), \balias\b(1)]" "[+SEE ALSO?\bsh\b(1), \balias\b(1)]"
; ;

View file

@ -85,7 +85,6 @@ extern int b_builtin(int, char*[],Shbltin_t*);
extern int b_cd(int, char*[],Shbltin_t*); extern int b_cd(int, char*[],Shbltin_t*);
extern int b_command(int, char*[],Shbltin_t*); extern int b_command(int, char*[],Shbltin_t*);
extern int b_getopts(int, char*[],Shbltin_t*); extern int b_getopts(int, char*[],Shbltin_t*);
extern int b_hash(int, char*[],Shbltin_t*);
extern int b_hist(int, char*[],Shbltin_t*); extern int b_hist(int, char*[],Shbltin_t*);
extern int b_let(int, char*[],Shbltin_t*); extern int b_let(int, char*[],Shbltin_t*);
extern int b_read(int, char*[],Shbltin_t*); extern int b_read(int, char*[],Shbltin_t*);

View file

@ -281,6 +281,7 @@ extern Namval_t *nv_open(const char*,Dt_t*,int);
extern void nv_putval(Namval_t*,const char*,int); extern void nv_putval(Namval_t*,const char*,int);
extern void nv_putv(Namval_t*,const char*,int,Namfun_t*); extern void nv_putv(Namval_t*,const char*,int,Namfun_t*);
extern int nv_rename(Namval_t*,int); extern int nv_rename(Namval_t*,int);
extern void nv_rehash(Namval_t*,void*);
extern int nv_scan(Dt_t*,void(*)(Namval_t*,void*),void*,int,int); extern int nv_scan(Dt_t*,void(*)(Namval_t*,void*),void*,int,int);
extern char *nv_setdisc(Namval_t*,const char*,Namval_t*,Namfun_t*); extern char *nv_setdisc(Namval_t*,const char*,Namval_t*,Namfun_t*);
extern void nv_setref(Namval_t*, Dt_t*,int); extern void nv_setref(Namval_t*, Dt_t*,int);

View file

@ -17,4 +17,4 @@
* David Korn <dgk@research.att.com> * * David Korn <dgk@research.att.com> *
* * * *
***********************************************************************/ ***********************************************************************/
#define SH_RELEASE "93u+m 2020-06-08" #define SH_RELEASE "93u+m 2020-06-10"

View file

@ -5555,7 +5555,7 @@ command and the original positional parameters are restored upon completion.
Otherwise the positional parameters are unchanged. Otherwise the positional parameters are unchanged.
The exit status is the exit status of the last command executed. The exit status is the exit status of the last command executed.
.TP .TP
\(dg\(dg \f3alias\fP \*(OK \f3\-ptx\fP \*(CK \*(OK \f2name\fP\*(OK \f3=\fP\f2value\^\fP \*(CK \*(CK .\|.\|. \f3alias\fP \*(OK \f3\-ptx\fP \*(CK \*(OK \f2name\fP\*(OK \f3=\fP\f2value\^\fP \*(CK \*(CK .\|.\|.
.B alias\^ .B alias\^
with no arguments prints the list of aliases with no arguments prints the list of aliases
in the form in the form
@ -5580,16 +5580,13 @@ A trailing space in
.I value\^ .I value\^
causes the next word to be checked for causes the next word to be checked for
alias substitution. alias substitution.
The obsolete With the
.B \-t .B \-t
option is used to set and list tracked aliases. option, each name is looked up as a command in
The value of a tracked alias is the full pathname .B $PATH
corresponding to the given and its path is added to the hash table as a 'tracked alias'.
.IR name . If no name is given, this prints the hash table. See
The value becomes undefined when the value of .BR hash.
.SM
.B PATH
is reset but the alias remains tracked.
Without the Without the
.B \-t .B \-t
option, option,
@ -6125,19 +6122,20 @@ The option
can only be specified as the first option. can only be specified as the first option.
.TP .TP
\f3hash\fP \*(OK \f3\-r\fP \f2\^\fP\*(CK \*(OK \f3utility\^\fP \*(CK \f3hash\fP \*(OK \f3\-r\fP \f2\^\fP\*(CK \*(OK \f3utility\^\fP \*(CK
The .B hash
.BR hash displays or modifies the hash table with the locations of recently used
command can be used to display or modify the hash table. programs. If given no arguments, it lists all command/path associations
The hash table is a list of the most recently used programs (a.k.a. 'tracked aliases') in the hash table. Otherwise,
and their locations. .B hash
If performs a
.B PATH
search for each
.I utility\^ .I utility\^
is supplied, supplied and adds the result to the hash table.
.BR hash The
will add that utility to the hash table.
If
.B \-r .B \-r
is selected, the hash table is reset. option empties the hash table. This can also be achieved by resetting
.BR PATH.
.TP .TP
.PD 0 .PD 0
\f3hist\fP \*(OK \f3\-e\fP \f2ename\^\fP \ \*(CK \*(OK \f3\-nlr\^\fP \*(CK \*(OK \f2first\^\fP \*(OK \f2last\^\fP \*(CK \*(CK \f3hist\fP \*(OK \f3\-e\fP \f2ename\^\fP \ \*(CK \*(OK \f3\-nlr\^\fP \*(CK \*(OK \f2first\^\fP \*(OK \f2last\^\fP \*(CK \*(CK

View file

@ -229,15 +229,6 @@ static int shlvl;
static int rand_shift; static int rand_shift;
/*
* Invalidate all path name bindings
*/
static void rehash(register Namval_t *np,void *data)
{
NOT_USED(data);
nv_onattr(np,NV_NOALIAS);
}
/* /*
* out of memory routine for stak routines * out of memory routine for stak routines
*/ */
@ -337,7 +328,8 @@ static void put_restricted(register Namval_t* np,const char *val,int flags,Namfu
errormsg(SH_DICT,ERROR_exit(1),e_restricted,nv_name(np)); errormsg(SH_DICT,ERROR_exit(1),e_restricted,nv_name(np));
if(np==PATHNOD || (path_scoped=(strcmp(name,PATHNOD->nvname)==0))) if(np==PATHNOD || (path_scoped=(strcmp(name,PATHNOD->nvname)==0)))
{ {
nv_scan(shp->track_tree,rehash,(void*)0,NV_TAGGED,NV_TAGGED); /* Clear the hash table */
nv_scan(shp->track_tree,nv_rehash,(void*)0,NV_TAGGED,NV_TAGGED);
if(path_scoped && !val) if(path_scoped && !val)
val = PATHNOD->nvalue.cp; val = PATHNOD->nvalue.cp;
} }

View file

@ -2317,6 +2317,15 @@ static int scanfilter(Dt_t *dict, void *arg, void *data)
return(0); return(0);
} }
/*
* Handler function to invalidate a path name binding in the hash table
*/
void nv_rehash(register Namval_t *np,void *data)
{
NOT_USED(data);
nv_onattr(np,NV_NOALIAS);
}
/* /*
* Walk through the name-value pairs * Walk through the name-value pairs
* if <mask> is non-zero, then only nodes with (nvflags&mask)==flags * if <mask> is non-zero, then only nodes with (nvflags&mask)==flags