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:
parent
74b4162178
commit
80d9ae2b1c
8 changed files with 68 additions and 98 deletions
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)]"
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
@ -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*);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue