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 
45 static 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  */
52 int	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  */
95 int	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 
133 static 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