1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-02-15 04:32:24 +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:
- 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
#!/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.

View file

@ -139,7 +139,7 @@ static int whence(Shell_t *shp,char **argv, register int flags)
register const char *msg;
Namval_t *nq;
char *notused;
Pathcomp_t *pp=0;
Pathcomp_t *pp;
if(flags&Q_FLAG)
flags &= ~A_FLAG;
while(name= *argv++)
@ -179,16 +179,24 @@ static int whence(Shell_t *shp,char **argv, register int flags)
bltins:
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)
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)
continue;
aflag++;
@ -210,6 +218,7 @@ static int whence(Shell_t *shp,char **argv, register int flags)
aflag++;
}
search:
pp = 0;
do
{
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 */
sfputr(sfstdout,sh_fmtq(cp),-1);
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');
}
}

View file

@ -1988,7 +1988,7 @@ _JOB_
;
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
"[+NAME?whence, type - locate a command and describe its type]"
"[+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_function[] = " is a function";
const char is_ufunction[] = " is an undefined function";
const char e_autoloadfrom[] = " (autoload from %s)";
#ifdef JOBS
# ifdef SIGTSTP
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_function[];
extern const char is_ufunction[];
extern const char e_autoloadfrom[];
#ifdef SHELLMAGIC
extern const char e_prohibited[];
#endif /* SHELLMAGIC */

View file

@ -29,6 +29,7 @@ Command=${0##*/}
integer Errors=0
[[ -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
[[ -s out1 ]] && err_exit 'type should not write on stdout for not found case'
@ -417,6 +418,8 @@ ${.sh.version}
END
) || err_exit '${.sh.xxx} variables causes cat not be found'
PATH=$PATH_orig
# ======
# Check that 'command -p' searches the default OS utility PATH.
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" \
"(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))