1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-02-13 11:42:21 +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));
}
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));
}

View file

@ -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)]"
;

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_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*);

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_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);

View file

@ -17,4 +17,4 @@
* 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.
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

View file

@ -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;
}

View file

@ -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 <mask> is non-zero, then only nodes with (nvflags&mask)==flags