]> git.ipfire.org Git - thirdparty/bash.git/blob - builtins/type.def
Imported from ../bash-2.03.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 1, 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, 675 Mass Ave, Cambridge, MA 02139, 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 /* For each word in LIST, find out what the shell is going to do with
70 it as a simple command. i.e., which file would this shell use to
71 execve, or if it is a builtin command, or an alias. Possible flag
72 arguments:
73 -t Returns the "type" of the object, one of
74 `alias', `keyword', `function', `builtin',
75 or `file'.
76
77 -p Returns the pathname of the file if -type is
78 a file.
79
80 -a Returns all occurrences of words, whether they
81 be a filename in the path, alias, function,
82 or builtin.
83 Order of evaluation:
84 alias
85 keyword
86 function
87 builtin
88 file
89 */
90
91 int
92 type_builtin (list)
93 WORD_LIST *list;
94 {
95 int path_only, type_only, all, verbose;
96 int successful_finds, opt;
97 WORD_LIST *prev, *this;
98
99 if (list == 0)
100 return (EXECUTION_SUCCESS);
101
102 path_only = type_only = all = 0;
103 successful_finds = 0;
104
105 /* Handle the obsolescent `-type', `-path', and `-all' by prescanning
106 the arguments and removing those options from the list before calling
107 internal_getopt. Recognize `--type', `--path', and `--all' also.
108 THIS SHOULD REALLY GO AWAY. */
109 for (this = list; this && this->word->word[0] == '-'; )
110 {
111 char *flag = &(this->word->word[1]);
112
113 if (STREQ (flag, "type") || STREQ (flag, "-type"))
114 {
115 type_only = 1;
116 path_only = 0;
117 }
118 else if (STREQ (flag, "path") || STREQ (flag, "-path"))
119 {
120 path_only = 1;
121 type_only = 0;
122 }
123 else if (STREQ (flag, "all") || STREQ (flag, "-all"))
124 all = 1;
125 else
126 {
127 prev = this;
128 this = this->next;
129 continue;
130 }
131
132 /* We found a long option; remove it from the argument list. Don't
133 free it if it's the head of the argument list, though -- the
134 argument list will be freed by the caller. */
135 if (this == list)
136 this = list = list->next;
137 else
138 {
139 prev->next = this->next;
140 this->next = (WORD_LIST *)NULL;
141 dispose_words (this);
142 this = prev->next;
143 }
144 }
145
146 reset_internal_getopt ();
147 while ((opt = internal_getopt (list, "apt")) != -1)
148 {
149 switch (opt)
150 {
151 case 't':
152 type_only = 1;
153 path_only = 0;
154 break;
155 case 'p':
156 path_only = 1;
157 type_only = 0;
158 break;
159 case 'a':
160 all = 1;
161 break;
162 default:
163 builtin_usage ();
164 return (EX_USAGE);
165 }
166 }
167 list = loptend;
168
169 if (type_only)
170 verbose = 1;
171 else if (path_only == 0)
172 verbose = 2;
173 else if (path_only)
174 verbose = 3;
175 else
176 verbose = 0;
177
178 while (list)
179 {
180 int found;
181
182 found = describe_command (list->word->word, verbose, all);
183
184 if (!found && !path_only && !type_only)
185 builtin_error ("%s: not found", list->word->word);
186
187 successful_finds += found;
188 list = list->next;
189 }
190
191 fflush (stdout);
192
193 return ((successful_finds != 0) ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
194 }
195
196 /*
197 * Describe COMMAND as required by the type builtin.
198 *
199 * If VERBOSE == 0, don't print anything
200 * If VERBOSE == 1, print short description as for `type -t'
201 * If VERBOSE == 2, print long description as for `type' and `command -V'
202 * If VERBOSE == 3, print path name only for disk files
203 * If VERBOSE == 4, print string used to invoke COMMAND, for `command -v'
204 *
205 * ALL says whether or not to look for all occurrences of COMMAND, or
206 * return after finding it once.
207 */
208 int
209 describe_command (command, verbose, all)
210 char *command;
211 int verbose, all;
212 {
213 int found, i, found_file;
214 char *full_path;
215 SHELL_VAR *func;
216 #if defined (ALIAS)
217 alias_t *alias;
218 #endif
219
220 found = found_file = 0;
221 full_path = (char *)NULL;
222
223 #if defined (ALIAS)
224 /* Command is an alias? */
225 alias = find_alias (command);
226
227 if (alias)
228 {
229 if (verbose == 1)
230 puts ("alias");
231 else if (verbose == 2)
232 printf ("%s is aliased to `%s'\n", command, alias->value);
233 else if (verbose == 4)
234 {
235 char *x = single_quote (alias->value);
236 printf ("alias %s=%s\n", command, x);
237 free (x);
238 }
239
240 found = 1;
241
242 if (all == 0)
243 return (1);
244 }
245 #endif /* ALIAS */
246
247 /* Command is a shell reserved word? */
248 i = find_reserved_word (command);
249 if (i >= 0)
250 {
251 if (verbose == 1)
252 puts ("keyword");
253 else if (verbose == 2)
254 printf ("%s is a shell keyword\n", command);
255 else if (verbose == 4)
256 printf ("%s\n", command);
257
258 found = 1;
259
260 if (all == 0)
261 return (1);
262 }
263
264 /* Command is a function? */
265 func = find_function (command);
266
267 if (func)
268 {
269 if (verbose == 1)
270 puts ("function");
271 else if (verbose == 2)
272 {
273 #define PRETTY_PRINT_FUNC 1
274 char *result;
275
276 printf ("%s is a function\n", command);
277
278 /* We're blowing away THE_PRINTED_COMMAND here... */
279
280 result = named_function_string (command,
281 (COMMAND *) function_cell (func),
282 PRETTY_PRINT_FUNC);
283 printf ("%s\n", result);
284 #undef PRETTY_PRINT_FUNC
285 }
286 else if (verbose == 4)
287 printf ("%s\n", command);
288
289 found = 1;
290
291 if (all == 0)
292 return (1);
293 }
294
295 /* Command is a builtin? */
296 if (find_shell_builtin (command))
297 {
298 if (verbose == 1)
299 puts ("builtin");
300 else if (verbose == 2)
301 printf ("%s is a shell builtin\n", command);
302 else if (verbose == 4)
303 printf ("%s\n", command);
304
305 found = 1;
306
307 if (all == 0)
308 return (1);
309 }
310
311 /* Command is a disk file? */
312 /* If the command name given is already an absolute command, just
313 check to see if it is executable. */
314 if (absolute_program (command))
315 {
316 int f = file_status (command);
317 if (f & FS_EXECABLE)
318 {
319 if (verbose == 1)
320 puts ("file");
321 else if (verbose == 2)
322 printf ("%s is %s\n", command, command);
323 else if (verbose == 3 || verbose == 4)
324 printf ("%s\n", command);
325
326 /* There's no use looking in the hash table or in $PATH,
327 because they're not consulted when an absolute program
328 name is supplied. */
329 return (1);
330 }
331 }
332
333 /* If the user isn't doing "-a", then we might care about
334 whether the file is present in our hash table. */
335 if (all == 0)
336 {
337 if ((full_path = find_hashed_filename (command)) != (char *)NULL)
338 {
339 if (verbose == 1)
340 puts ("file");
341 else if (verbose == 2)
342 printf ("%s is hashed (%s)\n", command, full_path);
343 else if (verbose == 3 || verbose == 4)
344 printf ("%s\n", full_path);
345
346 free (full_path);
347 return (1);
348 }
349 }
350
351 /* Now search through $PATH. */
352 while (1)
353 {
354 if (all == 0)
355 full_path = find_user_command (command);
356 else
357 full_path =
358 user_command_matches (command, FS_EXEC_ONLY, found_file);
359 /* XXX - should that be FS_EXEC_PREFERRED? */
360
361 if (!full_path)
362 break;
363
364 found_file++;
365 found = 1;
366
367 if (verbose == 1)
368 puts ("file");
369 else if (verbose == 2)
370 printf ("%s is %s\n", command, full_path);
371 else if (verbose == 3 || verbose == 4)
372 printf ("%s\n", full_path);
373
374 free (full_path);
375 full_path = (char *)NULL;
376
377 if (all == 0)
378 break;
379 }
380
381 return (found);
382 }