From 80d9ae2b1ce0550877bbf394bfb09b186df3cdac Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Thu, 11 Jun 2020 05:23:38 +0200 Subject: [PATCH] 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) --- src/cmd/ksh93/bltins/typeset.c | 74 +++++++++++--------------------- src/cmd/ksh93/data/builtins.c | 27 ++++++------ src/cmd/ksh93/include/builtins.h | 1 - src/cmd/ksh93/include/nval.h | 1 + src/cmd/ksh93/include/version.h | 2 +- src/cmd/ksh93/sh.1 | 40 ++++++++--------- src/cmd/ksh93/sh/init.c | 12 +----- src/cmd/ksh93/sh/name.c | 9 ++++ 8 files changed, 68 insertions(+), 98 deletions(-) diff --git a/src/cmd/ksh93/bltins/typeset.c b/src/cmd/ksh93/bltins/typeset.c index b22365650..c1b1c0cf2 100644 --- a/src/cmd/ksh93/bltins/typeset.c +++ b/src/cmd/ksh93/bltins/typeset.c @@ -133,56 +133,20 @@ int b_readonly(int argc,char *argv[],Shbltin_t *context) return(setall(argv,flag,tdata.sh->var_tree, &tdata)); } -int b_hash(int argc,char *argv[],Shbltin_t *context) -{ - register unsigned flag = NV_NOARRAY | NV_NOSCOPE | NV_ASSIGN | NV_TAGGED; - register Dt_t *troot; - register int rflag=0, n; - struct tdata tdata; - NOT_USED(argc); - 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); -} - +/* + * 'alias' and 'hash' builtins + */ +#if 0 + /* for the dictionary generator */ + int b_hash(int argc,register char *argv[],Shbltin_t *context){} +#endif 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 n; + register int rflag=0, n; struct tdata tdata; + Namval_t *np; NOT_USED(argc); memset((void*)&tdata,0,sizeof(tdata)); tdata.sh = context->shp; @@ -196,7 +160,7 @@ int b_alias(int argc,register char *argv[],Shbltin_t *context) *opt_info.option = 0; tdata.argnum = 0; 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': tdata.prefix = argv[0]; @@ -205,7 +169,10 @@ int b_alias(int argc,register char *argv[],Shbltin_t *context) flag |= NV_TAGGED; break; case 'x': - flag |= NV_EXPORT; + /* obsolete, ignored */ + break; + case 'r': + rflag=1; break; case ':': 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) errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*))); 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(); + /* '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)); } diff --git a/src/cmd/ksh93/data/builtins.c b/src/cmd/ksh93/data/builtins.c index 39c8724e8..4fefde993 100644 --- a/src/cmd/ksh93/data/builtins.c +++ b/src/cmd/ksh93/data/builtins.c @@ -78,8 +78,8 @@ const struct shtable3 shtab_builtins[] = #if _bin_newgrp || _usr_bin_newgrp "newgrp", NV_BLTIN|BLT_ENV|BLT_SPC, Bltin(login), #endif /* _bin_newgrp || _usr_bin_newgrp */ - "alias", NV_BLTIN|BLT_SPC, bltin(alias), - "hash", NV_BLTIN, bltin(hash), + "alias", NV_BLTIN, bltin(alias), + "hash", NV_BLTIN, bltin(alias), "enum", NV_BLTIN|BLT_ENV|BLT_SPC|BLT_DCL,bltin(enum), "eval", NV_BLTIN|BLT_ENV|BLT_SPC|BLT_EXIT,bltin(eval), "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_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 "[+NAME?alias - define or display aliases]" "[+DESCRIPTION?\balias\b creates or redefines alias definitions " @@ -363,10 +363,9 @@ USAGE_LICENSE "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 " "as input to the shell to recreate the current aliases.]" -"[t?Used for tracked aliases. These are aliases that connect a " - "command name to the pathname of the command and are reset " - "when the \bPATH\b variable is unset. The tracked aliases feature is " - "now obsolete.]" +"[t?Each \aname\a is looked up as a command in \b$PATH\b and its path is " + "added to the hash table as a 'tracked alias'. If no \aname\a is " + "given, this prints the hash table. See \bhash(1)\b.]" "[x?Ignored, this option is obsolete.]" "\n" "\n[name[=value]...]\n" @@ -932,13 +931,12 @@ _JOB_ const char sh_opthash[] = "[-1c?\n@(#)$Id: hash (ksh community) 2020-06-10 $\n]" "[+NAME?hash - display the locations of recently used programs]" -"[+DESCRIPTION?The \bhash\b utility is used to display or modify " - "the hash table, which contains the locations of " - "recently used programs. When \bhash\b is given no arguments, " - "it will list all commands in the hash table. If \autility\a is " - "supplied, \bhash\b will add that utility to the hash table.]" -"[r?This option will empty the hash table. The effect of " - "this flag can also be achieved by resetting the value of \bPATH\b.]" +"[+DESCRIPTION?\bhash\b displays or modifies the hash table with the " + "locations of recently used programs. If given no arguments, it lists " + "all command/path associations (a.k.a. 'tracked aliases') in the hash " + "table. Otherwise, \bhash\b performs a \bPATH\b search for each " + "\autility\a supplied and adds the result to the hash table.]" +"[r?Empty the hash table. This can also be achieved by resetting \bPATH\b.]" "\n" "\n[utility...]\n" "\n" @@ -946,7 +944,6 @@ const char sh_opthash[] = "[+0?Successful completion.]" "[+>0?An error occured.]" "}" - "[+SEE ALSO?\bsh\b(1), \balias\b(1)]" ; diff --git a/src/cmd/ksh93/include/builtins.h b/src/cmd/ksh93/include/builtins.h index a93cc9e70..680ab4adb 100644 --- a/src/cmd/ksh93/include/builtins.h +++ b/src/cmd/ksh93/include/builtins.h @@ -85,7 +85,6 @@ extern int b_builtin(int, char*[],Shbltin_t*); extern int b_cd(int, char*[],Shbltin_t*); extern int b_command(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_let(int, char*[],Shbltin_t*); extern int b_read(int, char*[],Shbltin_t*); diff --git a/src/cmd/ksh93/include/nval.h b/src/cmd/ksh93/include/nval.h index 71dfc8e13..04eebb4a6 100644 --- a/src/cmd/ksh93/include/nval.h +++ b/src/cmd/ksh93/include/nval.h @@ -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_putv(Namval_t*,const char*,int,Namfun_t*); 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 char *nv_setdisc(Namval_t*,const char*,Namval_t*,Namfun_t*); extern void nv_setref(Namval_t*, Dt_t*,int); diff --git a/src/cmd/ksh93/include/version.h b/src/cmd/ksh93/include/version.h index 06a3d6a92..3cb591b26 100644 --- a/src/cmd/ksh93/include/version.h +++ b/src/cmd/ksh93/include/version.h @@ -17,4 +17,4 @@ * David Korn * * * ***********************************************************************/ -#define SH_RELEASE "93u+m 2020-06-08" +#define SH_RELEASE "93u+m 2020-06-10" diff --git a/src/cmd/ksh93/sh.1 b/src/cmd/ksh93/sh.1 index 3136f0b3a..63899beac 100644 --- a/src/cmd/ksh93/sh.1 +++ b/src/cmd/ksh93/sh.1 @@ -5555,7 +5555,7 @@ command and the original positional parameters are restored upon completion. Otherwise the positional parameters are unchanged. The exit status is the exit status of the last command executed. .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\^ with no arguments prints the list of aliases in the form @@ -5580,16 +5580,13 @@ A trailing space in .I value\^ causes the next word to be checked for alias substitution. -The obsolete +With the .B \-t -option is used to set and list tracked aliases. -The value of a tracked alias is the full pathname -corresponding to the given -.IR name . -The value becomes undefined when the value of -.SM -.B PATH -is reset but the alias remains tracked. +option, each name is looked up as a command in +.B $PATH +and its path is added to the hash table as a 'tracked alias'. +If no name is given, this prints the hash table. See +.BR hash. Without the .B \-t option, @@ -6125,19 +6122,20 @@ The option can only be specified as the first option. .TP \f3hash\fP \*(OK \f3\-r\fP \f2\^\fP\*(CK \*(OK \f3utility\^\fP \*(CK -The -.BR hash -command can be used to display or modify the hash table. -The hash table is a list of the most recently used programs -and their locations. -If +.B hash +displays or modifies the hash table with the locations of recently used +programs. If given no arguments, it lists all command/path associations +(a.k.a. 'tracked aliases') in the hash table. Otherwise, +.B hash +performs a +.B PATH +search for each .I utility\^ -is supplied, -.BR hash -will add that utility to the hash table. -If +supplied and adds the result to the hash table. +The .B \-r -is selected, the hash table is reset. +option empties the hash table. This can also be achieved by resetting +.BR PATH. .TP .PD 0 \f3hist\fP \*(OK \f3\-e\fP \f2ename\^\fP \ \*(CK \*(OK \f3\-nlr\^\fP \*(CK \*(OK \f2first\^\fP \*(OK \f2last\^\fP \*(CK \*(CK diff --git a/src/cmd/ksh93/sh/init.c b/src/cmd/ksh93/sh/init.c index b21a9d258..5f1d5163d 100644 --- a/src/cmd/ksh93/sh/init.c +++ b/src/cmd/ksh93/sh/init.c @@ -229,15 +229,6 @@ static int shlvl; 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 */ @@ -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)); 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) val = PATHNOD->nvalue.cp; } diff --git a/src/cmd/ksh93/sh/name.c b/src/cmd/ksh93/sh/name.c index c7d40542d..a6f078c5f 100644 --- a/src/cmd/ksh93/sh/name.c +++ b/src/cmd/ksh93/sh/name.c @@ -2317,6 +2317,15 @@ static int scanfilter(Dt_t *dict, void *arg, void *data) 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 * if is non-zero, then only nodes with (nvflags&mask)==flags