1
0
Fork 0
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:
Martijn Dekker 2020-09-25 15:39:08 +02:00
parent cefe087d23
commit 3050bf28bc
6 changed files with 64 additions and 11 deletions

3
NEWS
View file

@ -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.

View file

@ -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, &notused)) && !is_abuiltin(np)) if(!(flags&F_FLAG) && (np = nv_bfsearch(name, shp->fun_tree, &nq, &notused)) && !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');
} }
} }

View file

@ -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 "

View file

@ -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...";

View file

@ -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 */

View file

@ -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))