mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
'whence -a' is documented to list all possible interpretations of a command, but failed to list a built-in command if a shell function by the same name exists or is marked undefined using 'autoload'. src/cmd/ksh93/bltins/whence.c: whence(): - Refactor and separate the code for reporting functions and built-in commands so that both can be reported for one name. src/cmd/ksh93/data/builtins.c: sh_optwhence[]: - Correct 'whence --man' to document that: * 'type' is equivalent to 'whence -v' * '-a' output is like '-v' src/cmd/ksh93/tests/builtins.sh: - Test 'whence -a' with these combinations: * a function, built-in and external command * an undefined/autoload function, built-in and external command Fixes https://github.com/ksh93/ksh/issues/83
295 lines
6.8 KiB
C
295 lines
6.8 KiB
C
/***********************************************************************
|
|
* *
|
|
* This software is part of the ast package *
|
|
* Copyright (c) 1982-2012 AT&T Intellectual Property *
|
|
* and is licensed under the *
|
|
* Eclipse Public License, Version 1.0 *
|
|
* by AT&T Intellectual Property *
|
|
* *
|
|
* A copy of the License is available at *
|
|
* http://www.eclipse.org/org/documents/epl-v10.html *
|
|
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
|
|
* *
|
|
* Information and Software Systems Research *
|
|
* AT&T Research *
|
|
* Florham Park NJ *
|
|
* *
|
|
* David Korn <dgk@research.att.com> *
|
|
* *
|
|
***********************************************************************/
|
|
#pragma prototyped
|
|
/*
|
|
* command [-pvVx] name [arg...]
|
|
* whence [-afvp] name...
|
|
*
|
|
* David Korn
|
|
* AT&T Labs
|
|
*
|
|
*/
|
|
|
|
#include "defs.h"
|
|
#include <error.h>
|
|
#include "shtable.h"
|
|
#include "name.h"
|
|
#include "path.h"
|
|
#include "shlex.h"
|
|
#include "builtins.h"
|
|
|
|
#define P_FLAG 1
|
|
#define V_FLAG 2
|
|
#define A_FLAG 4
|
|
#define F_FLAG 010
|
|
#define X_FLAG 020
|
|
#define Q_FLAG 040
|
|
|
|
static int whence(Shell_t *,char**, int);
|
|
|
|
/*
|
|
* command is called with argc==0 when checking for -V or -v option
|
|
* In this case return 0 when -v or -V or unknown option, otherwise
|
|
* the shift count to the command is returned
|
|
*/
|
|
int b_command(register int argc,char *argv[],Shbltin_t *context)
|
|
{
|
|
register int n, flags=0;
|
|
register Shell_t *shp = context->shp;
|
|
opt_info.index = opt_info.offset = 0;
|
|
while((n = optget(argv,sh_optcommand))) switch(n)
|
|
{
|
|
case 'p':
|
|
if(sh_isoption(SH_RESTRICTED))
|
|
errormsg(SH_DICT,ERROR_exit(1),e_restricted,"-p");
|
|
sh_onstate(SH_DEFPATH);
|
|
break;
|
|
case 'v':
|
|
flags |= X_FLAG;
|
|
break;
|
|
case 'V':
|
|
flags |= V_FLAG;
|
|
break;
|
|
case 'x':
|
|
shp->xargexit = 1;
|
|
break;
|
|
case ':':
|
|
if(argc==0)
|
|
return(0);
|
|
errormsg(SH_DICT,2, "%s", opt_info.arg);
|
|
break;
|
|
case '?':
|
|
if(argc==0)
|
|
return(0);
|
|
errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
|
|
break;
|
|
}
|
|
if(argc==0)
|
|
return(flags?0:opt_info.index);
|
|
argv += opt_info.index;
|
|
if(error_info.errors || !*argv)
|
|
errormsg(SH_DICT,ERROR_usage(2),"%s", optusage((char*)0));
|
|
return(whence(shp,argv, flags));
|
|
}
|
|
|
|
/*
|
|
* for the whence command
|
|
*/
|
|
int b_whence(int argc,char *argv[],Shbltin_t *context)
|
|
{
|
|
register int flags=0, n;
|
|
register Shell_t *shp = context->shp;
|
|
NOT_USED(argc);
|
|
if(*argv[0]=='t')
|
|
flags = V_FLAG;
|
|
while((n = optget(argv,sh_optwhence))) switch(n)
|
|
{
|
|
case 'a':
|
|
flags |= A_FLAG;
|
|
/* FALL THRU */
|
|
case 'v':
|
|
flags |= V_FLAG;
|
|
break;
|
|
case 'f':
|
|
flags |= F_FLAG;
|
|
break;
|
|
case 'p':
|
|
flags |= P_FLAG;
|
|
flags &= ~V_FLAG;
|
|
break;
|
|
case 'q':
|
|
flags |= Q_FLAG;
|
|
break;
|
|
case ':':
|
|
errormsg(SH_DICT,2, "%s", opt_info.arg);
|
|
break;
|
|
case '?':
|
|
errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
|
|
break;
|
|
}
|
|
argv += opt_info.index;
|
|
if(error_info.errors || !*argv)
|
|
errormsg(SH_DICT,ERROR_usage(2),optusage((char*)0));
|
|
return(whence(shp, argv, flags));
|
|
}
|
|
|
|
static int whence(Shell_t *shp,char **argv, register int flags)
|
|
{
|
|
register const char *name;
|
|
register Namval_t *np;
|
|
register const char *cp;
|
|
register int aflag,r=0;
|
|
register const char *msg;
|
|
int tofree;
|
|
Namval_t *nq;
|
|
char *notused;
|
|
Pathcomp_t *pp=0;
|
|
int notrack = 1;
|
|
if(flags&Q_FLAG)
|
|
flags &= ~A_FLAG;
|
|
while(name= *argv++)
|
|
{
|
|
tofree=0;
|
|
aflag = ((flags&A_FLAG)!=0);
|
|
cp = 0;
|
|
np = 0;
|
|
if(flags&P_FLAG)
|
|
goto search;
|
|
if(flags&Q_FLAG)
|
|
goto bltins;
|
|
/* reserved words first */
|
|
if(sh_lookup(name,shtab_reserved))
|
|
{
|
|
sfprintf(sfstdout,"%s%s\n",name,(flags&V_FLAG)?sh_translate(is_reserved):"");
|
|
if(!aflag)
|
|
continue;
|
|
aflag++;
|
|
}
|
|
/* non-tracked aliases */
|
|
if((np=nv_search(name,shp->alias_tree,0))
|
|
&& !nv_isnull(np) && !(notrack=nv_isattr(np,NV_TAGGED))
|
|
&& (cp=nv_getval(np)))
|
|
{
|
|
if(flags&V_FLAG)
|
|
{
|
|
msg = sh_translate(is_alias);
|
|
sfprintf(sfstdout,msg,name);
|
|
}
|
|
sfputr(sfstdout,sh_fmtq(cp),'\n');
|
|
if(!aflag)
|
|
continue;
|
|
cp = 0;
|
|
aflag++;
|
|
}
|
|
/* built-ins and functions next */
|
|
bltins:
|
|
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)
|
|
continue;
|
|
sfprintf(sfstdout,"%s%s\n",name,cp);
|
|
if(!aflag)
|
|
continue;
|
|
aflag++;
|
|
}
|
|
if((np = nv_bfsearch(name, shp->bltin_tree, &nq, ¬used)) && !nv_isnull(np))
|
|
{
|
|
if(flags&V_FLAG)
|
|
if(nv_isattr(np,BLT_SPC))
|
|
cp = sh_translate(is_spcbuiltin);
|
|
else
|
|
cp = sh_translate(is_builtin);
|
|
else
|
|
cp = "";
|
|
if(flags&Q_FLAG)
|
|
continue;
|
|
sfprintf(sfstdout,"%s%s\n",name,cp);
|
|
if(!aflag)
|
|
continue;
|
|
aflag++;
|
|
}
|
|
search:
|
|
if(sh_isstate(SH_DEFPATH))
|
|
{
|
|
cp=0;
|
|
notrack=1;
|
|
}
|
|
do
|
|
{
|
|
if(path_search(shp,name,&pp,2+(aflag>1)))
|
|
{
|
|
cp = name;
|
|
if((flags&P_FLAG) && *cp!='/')
|
|
cp = 0;
|
|
}
|
|
else
|
|
{
|
|
cp = stakptr(PATH_OFFSET);
|
|
if(*cp==0)
|
|
cp = 0;
|
|
else if(*cp!='/')
|
|
{
|
|
cp = path_fullname(shp,cp);
|
|
tofree=1;
|
|
}
|
|
}
|
|
if(flags&Q_FLAG)
|
|
{
|
|
pp = 0;
|
|
r |= !cp;
|
|
}
|
|
else if(cp)
|
|
{
|
|
if(flags&V_FLAG)
|
|
{
|
|
if(*cp!= '/')
|
|
{
|
|
if(!np && (np=nv_search(name,shp->track_tree,0)))
|
|
{
|
|
const char *command_path = np->nvalue.pathcomp->name;
|
|
sfprintf(sfstdout,"%s %s %s/%s\n",name,sh_translate(is_talias),command_path,cp);
|
|
}
|
|
continue;
|
|
}
|
|
sfputr(sfstdout,sh_fmtq(name),' ');
|
|
/* built-in version of program */
|
|
if(*cp=='/' && (np=nv_search(cp,shp->bltin_tree,0)))
|
|
msg = sh_translate(is_builtver);
|
|
/* tracked aliases next */
|
|
else if(aflag>1 || !notrack || strchr(name,'/'))
|
|
msg = sh_translate("is");
|
|
else
|
|
msg = sh_translate(is_talias);
|
|
sfputr(sfstdout,msg,' ');
|
|
}
|
|
sfputr(sfstdout,sh_fmtq(cp),'\n');
|
|
if(aflag)
|
|
{
|
|
if(aflag<=1)
|
|
aflag++;
|
|
if (pp)
|
|
pp = pp->next;
|
|
}
|
|
else
|
|
pp = 0;
|
|
if(tofree)
|
|
{
|
|
free((char*)cp);
|
|
tofree = 0;
|
|
}
|
|
}
|
|
else if(aflag<=1)
|
|
{
|
|
r |= 1;
|
|
if(flags&V_FLAG)
|
|
errormsg(SH_DICT,ERROR_exit(0),e_found,sh_fmtq(name));
|
|
}
|
|
} while(pp);
|
|
}
|
|
return(r);
|
|
}
|
|
|