mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
whence -v/-a: report path to autoloadable functions
Since at least 1999, whence -v on pdksh (and its successor mksh) reports the path where an autoloadable function may be found: $ mkdir ~/fun; FPATH=~/fun $ echo 'myfn() { echo hi; }' >~/fun/myfn $ whence -v myfn myfn is a undefined (autoload from /home/user/fun/myfn) function Whereas ksh93 only reports, rather uselessly: myfn is an undefined function As of this commit, whence -v/-a on ksh 93u+m does the same as pdksh, but with correct grammar: myfn is an undefined function (autoload from /home/user/fun/myfn) This may be a small violation of my own "no new features" policy for 93u+m, but I couldn't resist. This omission has been annoying me, and it's just embarrassing to lack a pdksh feature :) src/cmd/ksh93/include/path.h, src/cmd/ksh93/data/msg.c: - Add e_autoloadfrom[] = " (autoload from %s)" message. src/cmd/ksh93/bltins/whence.c: whence(): - Report the path (if any) when reporting an undefined function. This needs to be done in two places: 1. When a function has been explicitly marked undefined with 'autoload', we need to do a quick path_search() loop to find the path. (These undefined functions take precedence over regular commands, so are reported first.) 2. When a function is not explicitly autoloaded but merely available in $FPATH, that path search was already done, so all we need to do is report it. (These are reported last.) Note that the output remains as on 93u+ if no function definition file is found on $FPATH. This is also like pdksh/mksh. src/cmd/ksh93/data/builtins.c: - Bump 'whence' version date. The inline docs never detailed very exactly what 'whence -v' reports, so no need for further edits. src/cmd/ksh93/tests/path.sh: - Regress-test the new whence behaviour plus actual autoloading, including the command override behaviour of autoloaded functions.
This commit is contained in:
parent
cefe087d23
commit
3050bf28bc
6 changed files with 64 additions and 11 deletions
3
NEWS
3
NEWS
|
@ -5,6 +5,9 @@ Any uppercase BUG_* names are modernish shell bug IDs.
|
||||||
|
|
||||||
2020-09-25:
|
2020-09-25:
|
||||||
|
|
||||||
|
- whence -v/-a now reports the path to the file that an "undefined" (i.e.
|
||||||
|
autoloadable) function will be loaded from when invoked, if found in $FPATH.
|
||||||
|
|
||||||
- When ksh invoked a shell script that does not have a leading
|
- When ksh invoked a shell script that does not have a leading
|
||||||
#!/hashbang/path, 'ps' and /proc/<PID>/cmdline showed corrupted output if
|
#!/hashbang/path, 'ps' and /proc/<PID>/cmdline showed corrupted output if
|
||||||
the new script's command line was shorter than that of the invoking script.
|
the new script's command line was shorter than that of the invoking script.
|
||||||
|
|
|
@ -139,7 +139,7 @@ static int whence(Shell_t *shp,char **argv, register int flags)
|
||||||
register const char *msg;
|
register const char *msg;
|
||||||
Namval_t *nq;
|
Namval_t *nq;
|
||||||
char *notused;
|
char *notused;
|
||||||
Pathcomp_t *pp=0;
|
Pathcomp_t *pp;
|
||||||
if(flags&Q_FLAG)
|
if(flags&Q_FLAG)
|
||||||
flags &= ~A_FLAG;
|
flags &= ~A_FLAG;
|
||||||
while(name= *argv++)
|
while(name= *argv++)
|
||||||
|
@ -179,16 +179,24 @@ static int whence(Shell_t *shp,char **argv, register int flags)
|
||||||
bltins:
|
bltins:
|
||||||
if(!(flags&F_FLAG) && (np = nv_bfsearch(name, shp->fun_tree, &nq, ¬used)) && !is_abuiltin(np))
|
if(!(flags&F_FLAG) && (np = nv_bfsearch(name, shp->fun_tree, &nq, ¬used)) && !is_abuiltin(np))
|
||||||
{
|
{
|
||||||
if(flags&V_FLAG)
|
|
||||||
if(nv_isnull(np))
|
|
||||||
cp = sh_translate(is_ufunction);
|
|
||||||
else
|
|
||||||
cp = sh_translate(is_function);
|
|
||||||
else
|
|
||||||
cp = "";
|
|
||||||
if(flags&Q_FLAG)
|
if(flags&Q_FLAG)
|
||||||
continue;
|
continue;
|
||||||
sfprintf(sfstdout,"%s%s\n",name,cp);
|
sfputr(sfstdout,name,-1);
|
||||||
|
if(flags&V_FLAG)
|
||||||
|
{
|
||||||
|
if(nv_isnull(np))
|
||||||
|
{
|
||||||
|
sfprintf(sfstdout,sh_translate(is_ufunction));
|
||||||
|
pp = 0;
|
||||||
|
while(!path_search(shp,name,&pp,3) && pp && (pp = pp->next))
|
||||||
|
;
|
||||||
|
if(*stakptr(PATH_OFFSET)=='/')
|
||||||
|
sfprintf(sfstdout,sh_translate(e_autoloadfrom),sh_fmtq(stakptr(PATH_OFFSET)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
sfprintf(sfstdout,sh_translate(is_function));
|
||||||
|
}
|
||||||
|
sfputc(sfstdout,'\n');
|
||||||
if(!aflag)
|
if(!aflag)
|
||||||
continue;
|
continue;
|
||||||
aflag++;
|
aflag++;
|
||||||
|
@ -210,6 +218,7 @@ static int whence(Shell_t *shp,char **argv, register int flags)
|
||||||
aflag++;
|
aflag++;
|
||||||
}
|
}
|
||||||
search:
|
search:
|
||||||
|
pp = 0;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
int maybe_undef_fn = 0; /* flag for possible undefined (i.e. autoloadable) function */
|
int maybe_undef_fn = 0; /* flag for possible undefined (i.e. autoloadable) function */
|
||||||
|
@ -246,7 +255,10 @@ static int whence(Shell_t *shp,char **argv, register int flags)
|
||||||
/* Undefined/autoloadable function on FPATH */
|
/* Undefined/autoloadable function on FPATH */
|
||||||
sfputr(sfstdout,sh_fmtq(cp),-1);
|
sfputr(sfstdout,sh_fmtq(cp),-1);
|
||||||
if(flags&V_FLAG)
|
if(flags&V_FLAG)
|
||||||
sfputr(sfstdout,sh_translate(is_ufunction),-1);
|
{
|
||||||
|
sfprintf(sfstdout,sh_translate(is_ufunction));
|
||||||
|
sfprintf(sfstdout,sh_translate(e_autoloadfrom),sh_fmtq(stakptr(PATH_OFFSET)));
|
||||||
|
}
|
||||||
sfputc(sfstdout,'\n');
|
sfputc(sfstdout,'\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1988,7 +1988,7 @@ _JOB_
|
||||||
;
|
;
|
||||||
|
|
||||||
const char sh_optwhence[] =
|
const char sh_optwhence[] =
|
||||||
"[-1c?\n@(#)$Id: whence (AT&T Research/ksh93) 2020-07-20 $\n]"
|
"[-1c?\n@(#)$Id: whence (AT&T Research/ksh93) 2020-09-25 $\n]"
|
||||||
USAGE_LICENSE
|
USAGE_LICENSE
|
||||||
"[+NAME?whence, type - locate a command and describe its type]"
|
"[+NAME?whence, type - locate a command and describe its type]"
|
||||||
"[+DESCRIPTION?Without \b-v\b, \bwhence\b writes on standard output an "
|
"[+DESCRIPTION?Without \b-v\b, \bwhence\b writes on standard output an "
|
||||||
|
|
|
@ -141,6 +141,7 @@ const char is_alias[] = "%s is an alias for ";
|
||||||
const char is_talias[] = "is a tracked alias for";
|
const char is_talias[] = "is a tracked alias for";
|
||||||
const char is_function[] = " is a function";
|
const char is_function[] = " is a function";
|
||||||
const char is_ufunction[] = " is an undefined function";
|
const char is_ufunction[] = " is an undefined function";
|
||||||
|
const char e_autoloadfrom[] = " (autoload from %s)";
|
||||||
#ifdef JOBS
|
#ifdef JOBS
|
||||||
# ifdef SIGTSTP
|
# ifdef SIGTSTP
|
||||||
const char e_newtty[] = "Switching to new tty driver...";
|
const char e_newtty[] = "Switching to new tty driver...";
|
||||||
|
|
|
@ -129,6 +129,7 @@ extern const char is_reserved[];
|
||||||
extern const char is_talias[];
|
extern const char is_talias[];
|
||||||
extern const char is_function[];
|
extern const char is_function[];
|
||||||
extern const char is_ufunction[];
|
extern const char is_ufunction[];
|
||||||
|
extern const char e_autoloadfrom[];
|
||||||
#ifdef SHELLMAGIC
|
#ifdef SHELLMAGIC
|
||||||
extern const char e_prohibited[];
|
extern const char e_prohibited[];
|
||||||
#endif /* SHELLMAGIC */
|
#endif /* SHELLMAGIC */
|
||||||
|
|
|
@ -29,6 +29,7 @@ Command=${0##*/}
|
||||||
integer Errors=0
|
integer Errors=0
|
||||||
|
|
||||||
[[ -d $tmp && -w $tmp && $tmp == "$PWD" ]] || { err\_exit "$LINENO" '$tmp not set; run this from shtests. Aborting.'; exit 1; }
|
[[ -d $tmp && -w $tmp && $tmp == "$PWD" ]] || { err\_exit "$LINENO" '$tmp not set; run this from shtests. Aborting.'; exit 1; }
|
||||||
|
PATH_orig=$PATH
|
||||||
|
|
||||||
type /xxxxxx > out1 2> out2
|
type /xxxxxx > out1 2> out2
|
||||||
[[ -s out1 ]] && err_exit 'type should not write on stdout for not found case'
|
[[ -s out1 ]] && err_exit 'type should not write on stdout for not found case'
|
||||||
|
@ -417,6 +418,8 @@ ${.sh.version}
|
||||||
END
|
END
|
||||||
) || err_exit '${.sh.xxx} variables causes cat not be found'
|
) || err_exit '${.sh.xxx} variables causes cat not be found'
|
||||||
|
|
||||||
|
PATH=$PATH_orig
|
||||||
|
|
||||||
# ======
|
# ======
|
||||||
# Check that 'command -p' searches the default OS utility PATH.
|
# Check that 'command -p' searches the default OS utility PATH.
|
||||||
expect=/dev/null
|
expect=/dev/null
|
||||||
|
@ -448,6 +451,39 @@ actual=$(PATH=$tmp; redirect 2>&1; hash ls; command -p -v ls)
|
||||||
[[ $actual == "$expect" ]] || err_exit "'command -p -v' fails to search default path if tracked alias exists" \
|
[[ $actual == "$expect" ]] || err_exit "'command -p -v' fails to search default path if tracked alias exists" \
|
||||||
"(expected $(printf %q "$expect"), got $(printf %q "$actual"))"
|
"(expected $(printf %q "$expect"), got $(printf %q "$actual"))"
|
||||||
|
|
||||||
|
# ======
|
||||||
|
# Unlike pdksh, ksh93 didn't report the path to autoloadable functions, which was an annoying omission.
|
||||||
|
if ((.sh.version >= 20200925))
|
||||||
|
then fundir=$tmp/whencefun
|
||||||
|
mkdir $fundir
|
||||||
|
echo "whence_FPATH_test() { echo I\'m just on FPATH; }" >$fundir/whence_FPATH_test
|
||||||
|
echo "whence_autoload_test() { echo I was explicitly autoloaded; }" >$fundir/whence_autoload_test
|
||||||
|
echo "function chmod { echo Hi, I\'m your new chmod!; }" >$fundir/chmod
|
||||||
|
echo "function ls { echo Hi, I\'m your new ls!; }" >$fundir/ls
|
||||||
|
hash -r
|
||||||
|
actual=$("$SHELL" -c 'FPATH=$1
|
||||||
|
autoload chmod whence_autoload_test
|
||||||
|
whence -a chmod whence_FPATH_test whence_autoload_test ls cp
|
||||||
|
whence_FPATH_test
|
||||||
|
whence_autoload_test
|
||||||
|
cp --totally-invalid-option 2>/dev/null
|
||||||
|
ls --totally-invalid-option 2>/dev/null
|
||||||
|
chmod --totally-invalid-option' \
|
||||||
|
whence_autoload_test "$fundir" 2>&1)
|
||||||
|
expect="chmod is an undefined function (autoload from $fundir/chmod)"
|
||||||
|
expect+=$'\n'"chmod is ${ whence -p chmod; }"
|
||||||
|
expect+=$'\n'"whence_FPATH_test is an undefined function (autoload from $fundir/whence_FPATH_test)"
|
||||||
|
expect+=$'\n'"whence_autoload_test is an undefined function (autoload from $fundir/whence_autoload_test)"
|
||||||
|
expect+=$'\n'"ls is a tracked alias for ${ whence -p ls; }"
|
||||||
|
expect+=$'\n'"ls is an undefined function (autoload from $fundir/ls)"
|
||||||
|
expect+=$'\n'"cp is a tracked alias for ${ whence -p cp; }"
|
||||||
|
expect+=$'\n'"I'm just on FPATH"
|
||||||
|
expect+=$'\n'"I was explicitly autoloaded"
|
||||||
|
expect+=$'\n'"Hi, I'm your new chmod!"
|
||||||
|
[[ $actual == "$expect" ]] || err_exit "failure in reporting or running autoloadable functions" \
|
||||||
|
"(expected $(printf %q "$expect"), got $(printf %q "$actual"))"
|
||||||
|
fi
|
||||||
|
|
||||||
# ======
|
# ======
|
||||||
exit $((Errors<125?Errors:125))
|
exit $((Errors<125?Errors:125))
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue