1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1982-2012 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                 Eclipse Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*          http://www.eclipse.org/org/documents/epl-v10.html           *
11*         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12*                                                                      *
13*              Information and Software Systems Research               *
14*                            AT&T Research                             *
15*                           Florham Park NJ                            *
16*                                                                      *
17*                  David Korn <dgk@research.att.com>                   *
18*                                                                      *
19***********************************************************************/
20#pragma prototyped
21/*
22 * command [-pvVx] name [arg...]
23 * whence [-afvp] name...
24 *
25 *   David Korn
26 *   AT&T Labs
27 *
28 */
29
30#include	"defs.h"
31#include	<error.h>
32#include	"shtable.h"
33#include	"name.h"
34#include	"path.h"
35#include	"shlex.h"
36#include	"builtins.h"
37
38#define P_FLAG	1
39#define V_FLAG	2
40#define A_FLAG	4
41#define F_FLAG	010
42#define X_FLAG	020
43#define Q_FLAG	040
44
45static int whence(Shell_t *,char**, int);
46
47/*
48 * command is called with argc==0 when checking for -V or -v option
49 * In this case return 0 when -v or -V or unknown option, otherwise
50 *   the shift count to the command is returned
51 */
52int	b_command(register int argc,char *argv[],Shbltin_t *context)
53{
54	register int n, flags=0;
55	register Shell_t *shp = context->shp;
56	opt_info.index = opt_info.offset = 0;
57	while((n = optget(argv,sh_optcommand))) switch(n)
58	{
59	    case 'p':
60		if(sh_isoption(SH_RESTRICTED))
61			 errormsg(SH_DICT,ERROR_exit(1),e_restricted,"-p");
62		sh_onstate(SH_DEFPATH);
63		break;
64	    case 'v':
65		flags |= X_FLAG;
66		break;
67	    case 'V':
68		flags |= V_FLAG;
69		break;
70	    case 'x':
71		shp->xargexit = 1;
72		break;
73	    case ':':
74		if(argc==0)
75			return(0);
76		errormsg(SH_DICT,2, "%s", opt_info.arg);
77		break;
78	    case '?':
79		if(argc==0)
80			return(0);
81		errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
82		break;
83	}
84	if(argc==0)
85		return(flags?0:opt_info.index);
86	argv += opt_info.index;
87	if(error_info.errors || !*argv)
88		errormsg(SH_DICT,ERROR_usage(2),"%s", optusage((char*)0));
89	return(whence(shp,argv, flags));
90}
91
92/*
93 *  for the whence command
94 */
95int	b_whence(int argc,char *argv[],Shbltin_t *context)
96{
97	register int flags=0, n;
98	register Shell_t *shp = context->shp;
99	NOT_USED(argc);
100	if(*argv[0]=='t')
101		flags = V_FLAG;
102	while((n = optget(argv,sh_optwhence))) switch(n)
103	{
104	    case 'a':
105		flags |= A_FLAG;
106		/* FALL THRU */
107	    case 'v':
108		flags |= V_FLAG;
109		break;
110	    case 'f':
111		flags |= F_FLAG;
112		break;
113	    case 'p':
114		flags |= P_FLAG;
115		flags &= ~V_FLAG;
116		break;
117	    case 'q':
118		flags |= Q_FLAG;
119		break;
120	    case ':':
121		errormsg(SH_DICT,2, "%s", opt_info.arg);
122		break;
123	    case '?':
124		errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
125		break;
126	}
127	argv += opt_info.index;
128	if(error_info.errors || !*argv)
129		errormsg(SH_DICT,ERROR_usage(2),optusage((char*)0));
130	return(whence(shp, argv, flags));
131}
132
133static int whence(Shell_t *shp,char **argv, register int flags)
134{
135	register const char *name;
136	register Namval_t *np;
137	register const char *cp;
138	register int aflag,r=0;
139	register const char *msg;
140	int	tofree;
141	Dt_t *root;
142	Namval_t *nq;
143	char *notused;
144	Pathcomp_t *pp=0;
145	int notrack = 1;
146	if(flags&Q_FLAG)
147		flags &= ~A_FLAG;
148	while(name= *argv++)
149	{
150		tofree=0;
151		aflag = ((flags&A_FLAG)!=0);
152		cp = 0;
153		np = 0;
154		if(flags&P_FLAG)
155			goto search;
156		if(flags&Q_FLAG)
157			goto bltins;
158		/* reserved words first */
159		if(sh_lookup(name,shtab_reserved))
160		{
161			sfprintf(sfstdout,"%s%s\n",name,(flags&V_FLAG)?sh_translate(is_reserved):"");
162			if(!aflag)
163				continue;
164			aflag++;
165		}
166		/* non-tracked aliases */
167		if((np=nv_search(name,shp->alias_tree,0))
168			&& !nv_isnull(np) && !(notrack=nv_isattr(np,NV_TAGGED))
169			&& (cp=nv_getval(np)))
170		{
171			if(flags&V_FLAG)
172			{
173				if(nv_isattr(np,NV_EXPORT))
174					msg = sh_translate(is_xalias);
175				else
176					msg = sh_translate(is_alias);
177				sfprintf(sfstdout,msg,name);
178			}
179			sfputr(sfstdout,sh_fmtq(cp),'\n');
180			if(!aflag)
181				continue;
182			cp = 0;
183			aflag++;
184		}
185		/* built-ins and functions next */
186	bltins:
187		root = (flags&F_FLAG)?shp->bltin_tree:shp->fun_tree;
188		if(np= nv_bfsearch(name, root, &nq, &notused))
189		{
190			if(is_abuiltin(np) && nv_isnull(np))
191				goto search;
192			cp = "";
193			if(flags&V_FLAG)
194			{
195				if(nv_isnull(np))
196					cp = sh_translate(is_ufunction);
197				else if(is_abuiltin(np))
198				{
199					if(nv_isattr(np,BLT_SPC))
200						cp = sh_translate(is_spcbuiltin);
201					else
202						cp = sh_translate(is_builtin);
203				}
204				else
205					cp = sh_translate(is_function);
206			}
207			if(flags&Q_FLAG)
208				continue;
209			sfprintf(sfstdout,"%s%s\n",name,cp);
210			if(!aflag)
211				continue;
212			cp = 0;
213			aflag++;
214		}
215	search:
216		if(sh_isstate(SH_DEFPATH))
217		{
218			cp=0;
219			notrack=1;
220		}
221		do
222		{
223			if(path_search(shp,name,&pp,2+(aflag>1)))
224			{
225				cp = name;
226				if((flags&P_FLAG) && *cp!='/')
227					cp = 0;
228			}
229			else
230			{
231				cp = stakptr(PATH_OFFSET);
232				if(*cp==0)
233					cp = 0;
234				else if(*cp!='/')
235				{
236					cp = path_fullname(shp,cp);
237					tofree=1;
238				}
239			}
240			if(flags&Q_FLAG)
241			{
242				pp = 0;
243				r |= !cp;
244			}
245			else if(cp)
246			{
247				if(flags&V_FLAG)
248				{
249					if(*cp!= '/')
250					{
251						if(!np && (np=nv_search(name,shp->track_tree,0)))
252							sfprintf(sfstdout,"%s %s %s/%s\n",name,sh_translate(is_talias),path_pwd(shp,0),cp);
253						else if(!np || nv_isnull(np))
254							sfprintf(sfstdout,"%s%s\n",name,sh_translate(is_ufunction));
255						continue;
256					}
257					sfputr(sfstdout,sh_fmtq(name),' ');
258					/* built-in version of program */
259					if(*cp=='/' && (np=nv_search(cp,shp->bltin_tree,0)))
260						msg = sh_translate(is_builtver);
261					/* tracked aliases next */
262					else if(aflag>1 || !notrack || strchr(name,'/'))
263						msg = sh_translate("is");
264					else
265						msg = sh_translate(is_talias);
266					sfputr(sfstdout,msg,' ');
267				}
268				sfputr(sfstdout,sh_fmtq(cp),'\n');
269				if(aflag)
270				{
271					if(aflag<=1)
272						aflag++;
273					if (pp)
274						pp = pp->next;
275				}
276				else
277					pp = 0;
278				if(tofree)
279				{
280					free((char*)cp);
281					tofree = 0;
282				}
283			}
284			else if(aflag<=1)
285			{
286				r |= 1;
287				if(flags&V_FLAG)
288					 errormsg(SH_DICT,ERROR_exit(0),e_found,sh_fmtq(name));
289			}
290		} while(pp);
291	}
292	return(r);
293}
294
295