]> git.ipfire.org Git - thirdparty/bash.git/blob - builtins/type.def
Imported from ../bash-2.05.tar.gz.
[thirdparty/bash.git] / builtins / type.def
1 This file is type.def, from which is created type.c.
2 It implements the builtin "type" in Bash.
3
4 Copyright (C) 1987, 1989, 1991, 1992 Free Software Foundation, Inc.
5
6 This file is part of GNU Bash, the Bourne Again SHell.
7
8 Bash is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
12
13 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with Bash; see the file COPYING. If not, write to the Free Software
20 Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
21
22 $PRODUCES type.c
23
24 $BUILTIN type
25 $FUNCTION type_builtin
26 $SHORT_DOC type [-apt] name [name ...]
27 For each NAME, indicate how it would be interpreted if used as a
28 command name.
29
30 If the -t option is used, `type' outputs a single word which is one of
31 `alias', `keyword', `function', `builtin', `file' or `', if NAME is an
32 alias, shell reserved word, shell function, shell builtin, disk file,
33 or unfound, respectively.
34
35 If the -p flag is used, `type' either returns the name of the disk
36 file that would be executed, or nothing if `type -t NAME' would not
37 return `file'.
38
39 If the -a flag is used, `type' displays all of the places that contain
40 an executable named `file'. This includes aliases and functions, if
41 and only if the -p flag is not also used.
42 $END
43
44 #include <config.h>
45
46 #include "../bashtypes.h"
47 #include "posixstat.h"
48
49 #if defined (HAVE_UNISTD_H)
50 # include <unistd.h>
51 #endif
52
53 #include <stdio.h>
54 #include "../bashansi.h"
55
56 #include "../shell.h"
57 #include "../findcmd.h"
58 #include "../hashcmd.h"
59
60 #if defined (ALIAS)
61 #include "../alias.h"
62 #endif /* ALIAS */
63
64 #include "common.h"
65 #include "bashgetopt.h"
66
67 extern int find_reserved_word ();
68
69 extern char *this_command_name;
70
71 /* For each word in LIST, find out what the shell is going to do with
72 it as a simple command. i.e., which file would this shell use to
73 execve, or if it is a builtin command, or an alias. Possible flag
74 arguments:
75 -t Returns the "type" of the object, one of
76 `alias', `keyword', `function', `builtin',
77 or `file'.
78
79 -p Returns the pathname of the file if -type is
80 a file.
81
82 -a Returns all occurrences of words, whether they
83 be a filename in the path, alias, function,
84 or builtin.
85 Order of evaluation:
86 alias
87 keyword
88 function
89 builtin
90 file
91 */
92
93 int
94 type_builtin (list)
95 WORD_LIST *list;
96 {
97 int path_only, type_only, all, verbose;
98 int successful_finds, opt;
99 WORD_LIST *prev, *this;
100
101 if (list == 0)
102 return (EXECUTION_SUCCESS);
103
104 path_only = type_only = all = 0;
105 successful_finds = 0;
106
107 /* Handle the obsolescent `-type', `-path', and `-all' by prescanning
108 the arguments and removing those options from the list before calling
109 internal_getopt. Recognize `--type', `--path', and `--all' also.
110 THIS SHOULD REALLY GO AWAY. */
111 for (this = list; this && this->word->word[0] == '-'; )
112 {
113 char *flag = &(this->word->word[1]);
114
115 if (STREQ (flag, "type") || STREQ (flag, "-type"))
116 {
117 type_only = 1;
118 path_only = 0;
119 }
120 else if (STREQ (flag, "path") || STREQ (flag, "-path"))
121 {
122 path_only = 1;
123 type_only = 0;
124 }
125 else if (STREQ (flag, "all") || STREQ (flag, "-all"))
126 all = 1;
127 else
128 {
129 prev = this;
130 this = this->next;
131 continue;
132 }
133
134 /* We found a long option; remove it from the argument list. Don't
135 free it if it's the head of the argument list, though -- the
136 argument list will be freed by the caller. */
137 if (this == list)
138 this = list = list->next;
139 else
140 {
141 prev->next = this->next;
142 this->next = (WORD_LIST *)NULL;
143 dispose_words (this);
144 this = prev->next;
145 }
146 }
147
148 reset_internal_getopt ();
149 while ((opt = internal_getopt (list, "apt")) != -1)
150 {
151 switch (opt)
152 {
153 case 't':
154 type_only = 1;
155 path_only = 0;
156 break;
157 case 'p':
158 path_only = 1;
159 type_only = 0;
160 break;
161 case 'a':
162 all = 1;
163 break;
164 default:
165 builtin_usage ();
166 return (EX_USAGE);
167 }
168 }
169 list = loptend;
170
171 if (type_only)
172 verbose = 1;
173 else if (path_only == 0)
174 verbose = 2;
175 else if (path_only)
176 verbose = 3;
177 else
178 verbose = 0;
179
180 while (list)
181 {
182 int found;
183
184 found = describe_command (list->word->word, verbose, all);
185
186 if (!found && !path_only && !type_only)
187 builtin_error ("%s: not found", list->word->word);
188
189 successful_finds += found;
190 list = list->next;
191 }
192
193 fflush (stdout);
194
195 return ((successful_finds != 0) ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
196 }
197
198 /*
199 * Describe COMMAND as required by the type builtin.
200 *
201 * If VERBOSE == 0, don't print anything
202 * If VERBOSE == 1, print short description as for `type -t'
203 * If VERBOSE == 2, print long description as for `type' and `command -V'
204 * If VERBOSE == 3, print path name only for disk files
205 * If VERBOSE == 4, print string used to invoke COMMAND, for `command -v'
206 *
207 * ALL says whether or not to look for all occurrences of COMMAND, or
208 * return after finding it once.
209 */
210 int
211 describe_command (command, verbose, all)
212 char *command;
213 int verbose, all;
214 {
215 int found, i, found_file, f;
216 char *full_path, *x, *cwd;
217 SHELL_VAR *func;
218 #if defined (ALIAS)
219 alias_t *alias;
220 #endif
221
222 found = found_file = 0;
223 full_path = (char *)NULL;
224
225 #if defined (ALIAS)
226 /* Command is an alias? */
227 alias = find_alias (command);
228
229 if (alias)
230 {
231 if (verbose == 1)
232 puts ("alias");
233 else if (verbose == 2)
234 printf ("%s is aliased to `%s'\n", command, alias->value);
235 else if (verbose == 4)
236 {
237 x = sh_single_quote (alias->value);
238 printf ("alias %s=%s\n", command, x);
239 free (x);
240 }
241
242 found = 1;
243
244 if (all == 0)
245 return (1);
246 }
247 #endif /* ALIAS */
248
249 /* Command is a shell reserved word? */
250 i = find_reserved_word (command);
251 if (i >= 0)
252 {
253 if (verbose == 1)
254 puts ("keyword");
255 else if (verbose == 2)
256 printf ("%s is a shell keyword\n", command);
257 else if (verbose == 4)
258 printf ("%s\n", command);
259
260 found = 1;
261
262 if (all == 0)
263 return (1);
264 }
265
266 /* Command is a function? */
267 func = find_function (command);
268
269 if (func)
270 {
271 if (verbose == 1)
272 puts ("function");
273 else if (verbose == 2)
274 {
275 #define PRETTY_PRINT_FUNC 1
276 char *result;
277
278 printf ("%s is a function\n", command);
279
280 /* We're blowing away THE_PRINTED_COMMAND here... */
281
282 result = named_function_string (command,
283 (COMMAND *) function_cell (func),
284 PRETTY_PRINT_FUNC);
285 printf ("%s\n", result);
286 #undef PRETTY_PRINT_FUNC
287 }
288 else if (verbose == 4)
289 printf ("%s\n", command);
290
291 found = 1;
292
293 if (all == 0)
294 return (1);
295 }
296
297 /* Command is a builtin? */
298 if (find_shell_builtin (command))
299 {
300 if (verbose == 1)
301 puts ("builtin");
302 else if (verbose == 2)
303 printf ("%s is a shell builtin\n", command);
304 else if (verbose == 4)
305 printf ("%s\n", command);
306
307 found = 1;
308
309 if (all == 0)
310 return (1);
311 }
312
313 /* Command is a disk file? */
314 /* If the command name given is already an absolute command, just
315 check to see if it is executable. */
316 if (absolute_program (command))
317 {
318 f = file_status (command);
319 if (f & FS_EXECABLE)
320 {
321 if (verbose == 1)
322 puts ("file");
323 else if (verbose == 2)
324 printf ("%s is %s\n", command, command);
325 else if (verbose == 3 || verbose == 4)
326 printf ("%s\n", command);
327
328 /* There's no use looking in the hash table or in $PATH,
329 because they're not consulted when an absolute program
330 name is supplied. */
331 return (1);
332 }
333 }
334
335 /* If the user isn't doing "-a", then we might care about
336 whether the file is present in our hash table. */
337 if (all == 0)
338 {
339 if ((full_path = find_hashed_filename (command)) != (char *)NULL)
340 {
341 if (verbose == 1)
342 puts ("file");
343 else if (verbose == 2)
344 printf ("%s is hashed (%s)\n", command, full_path);
345 else if (verbose == 3 || verbose == 4)
346 printf ("%s\n", full_path);
347
348 free (full_path);
349 return (1);
350 }
351 }
352
353 /* Now search through $PATH. */
354 while (1)
355 {
356 if (all == 0)
357 full_path = find_user_command (command);
358 else
359 full_path =
360 user_command_matches (command, FS_EXEC_ONLY, found_file);
361 /* XXX - should that be FS_EXEC_PREFERRED? */
362
363 if (!full_path)
364 break;
365
366 /* If we found the command as itself by looking through $PATH, it
367 probably doesn't exist. Check whether or not the command is an
368 executable file. If it's not, don't report a match. */
369 if (STREQ (full_path, command))
370 {
371 f = file_status (full_path);
372 if ((f & FS_EXECABLE) == 0)
373 {
374 free (full_path);
375 full_path = (char *)NULL;
376 if (all == 0)
377 break;
378 }
379 else if (verbose >= 2)
380 full_path = sh_makepath ((char *)NULL, full_path, MP_DOCWD);
381 }
382
383 found_file++;
384 found = 1;
385
386 if (verbose == 1)
387 puts ("file");
388 else if (verbose == 2)
389 printf ("%s is %s\n", command, full_path);
390 else if (verbose == 3 || verbose == 4)
391 printf ("%s\n", full_path);
392
393 free (full_path);
394 full_path = (char *)NULL;
395
396 if (all == 0)
397 break;
398 }
399
400 return (found);
401 }