]>
Commit | Line | Data |
---|---|---|
726f6388 JA |
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 | |
bb70624e | 10 | Software Foundation; either version 2, or (at your option) any later |
726f6388 JA |
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 | |
bb70624e | 20 | Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. |
726f6388 JA |
21 | |
22 | $PRODUCES type.c | |
23 | ||
24 | $BUILTIN type | |
25 | $FUNCTION type_builtin | |
ccc6cda3 | 26 | $SHORT_DOC type [-apt] name [name ...] |
726f6388 JA |
27 | For each NAME, indicate how it would be interpreted if used as a |
28 | command name. | |
29 | ||
cce855bc | 30 | If the -t option is used, `type' outputs a single word which is one of |
726f6388 JA |
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 | ||
cce855bc JA |
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'. | |
726f6388 | 38 | |
cce855bc JA |
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. | |
726f6388 JA |
42 | $END |
43 | ||
ccc6cda3 JA |
44 | #include <config.h> |
45 | ||
46 | #include "../bashtypes.h" | |
bb70624e | 47 | #include "posixstat.h" |
ccc6cda3 JA |
48 | |
49 | #if defined (HAVE_UNISTD_H) | |
50 | # include <unistd.h> | |
51 | #endif | |
52 | ||
53 | #include <stdio.h> | |
54 | #include "../bashansi.h" | |
55 | ||
726f6388 | 56 | #include "../shell.h" |
cce855bc | 57 | #include "../findcmd.h" |
d166f048 | 58 | #include "../hashcmd.h" |
726f6388 JA |
59 | |
60 | #if defined (ALIAS) | |
61 | #include "../alias.h" | |
62 | #endif /* ALIAS */ | |
63 | ||
64 | #include "common.h" | |
b72432fd | 65 | #include "bashgetopt.h" |
726f6388 | 66 | |
ccc6cda3 | 67 | extern int find_reserved_word (); |
726f6388 | 68 | |
bb70624e JA |
69 | extern char *this_command_name; |
70 | ||
726f6388 JA |
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: | |
b72432fd | 75 | -t Returns the "type" of the object, one of |
726f6388 JA |
76 | `alias', `keyword', `function', `builtin', |
77 | or `file'. | |
78 | ||
b72432fd | 79 | -p Returns the pathname of the file if -type is |
726f6388 JA |
80 | a file. |
81 | ||
b72432fd | 82 | -a Returns all occurrences of words, whether they |
726f6388 JA |
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 | */ | |
b72432fd | 92 | |
ccc6cda3 | 93 | int |
726f6388 JA |
94 | type_builtin (list) |
95 | WORD_LIST *list; | |
96 | { | |
97 | int path_only, type_only, all, verbose; | |
b72432fd JA |
98 | int successful_finds, opt; |
99 | WORD_LIST *prev, *this; | |
726f6388 | 100 | |
ccc6cda3 JA |
101 | if (list == 0) |
102 | return (EXECUTION_SUCCESS); | |
103 | ||
726f6388 JA |
104 | path_only = type_only = all = 0; |
105 | successful_finds = 0; | |
106 | ||
b72432fd JA |
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] == '-'; ) | |
726f6388 | 112 | { |
b72432fd | 113 | char *flag = &(this->word->word[1]); |
726f6388 | 114 | |
b72432fd | 115 | if (STREQ (flag, "type") || STREQ (flag, "-type")) |
726f6388 JA |
116 | { |
117 | type_only = 1; | |
118 | path_only = 0; | |
119 | } | |
b72432fd | 120 | else if (STREQ (flag, "path") || STREQ (flag, "-path")) |
726f6388 JA |
121 | { |
122 | path_only = 1; | |
123 | type_only = 0; | |
124 | } | |
b72432fd | 125 | else if (STREQ (flag, "all") || STREQ (flag, "-all")) |
28ef6c31 | 126 | all = 1; |
b72432fd | 127 | else |
726f6388 | 128 | { |
28ef6c31 JA |
129 | prev = this; |
130 | this = this->next; | |
131 | continue; | |
726f6388 | 132 | } |
b72432fd JA |
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; | |
726f6388 JA |
139 | else |
140 | { | |
b72432fd JA |
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: | |
ccc6cda3 | 165 | builtin_usage (); |
726f6388 JA |
166 | return (EX_USAGE); |
167 | } | |
726f6388 | 168 | } |
b72432fd | 169 | list = loptend; |
726f6388 JA |
170 | |
171 | if (type_only) | |
172 | verbose = 1; | |
ccc6cda3 | 173 | else if (path_only == 0) |
726f6388 JA |
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 | ||
b72432fd | 195 | return ((successful_finds != 0) ? EXECUTION_SUCCESS : EXECUTION_FAILURE); |
726f6388 JA |
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 | */ | |
ccc6cda3 | 210 | int |
726f6388 JA |
211 | describe_command (command, verbose, all) |
212 | char *command; | |
213 | int verbose, all; | |
214 | { | |
bb70624e JA |
215 | int found, i, found_file, f; |
216 | char *full_path, *x, *cwd; | |
726f6388 | 217 | SHELL_VAR *func; |
ccc6cda3 JA |
218 | #if defined (ALIAS) |
219 | alias_t *alias; | |
220 | #endif | |
221 | ||
222 | found = found_file = 0; | |
223 | full_path = (char *)NULL; | |
726f6388 JA |
224 | |
225 | #if defined (ALIAS) | |
226 | /* Command is an alias? */ | |
ccc6cda3 | 227 | alias = find_alias (command); |
726f6388 JA |
228 | |
229 | if (alias) | |
230 | { | |
231 | if (verbose == 1) | |
ccc6cda3 | 232 | puts ("alias"); |
726f6388 JA |
233 | else if (verbose == 2) |
234 | printf ("%s is aliased to `%s'\n", command, alias->value); | |
235 | else if (verbose == 4) | |
236 | { | |
28ef6c31 | 237 | x = sh_single_quote (alias->value); |
726f6388 JA |
238 | printf ("alias %s=%s\n", command, x); |
239 | free (x); | |
240 | } | |
241 | ||
242 | found = 1; | |
243 | ||
b72432fd | 244 | if (all == 0) |
726f6388 JA |
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) | |
ccc6cda3 | 254 | puts ("keyword"); |
726f6388 JA |
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 | ||
b72432fd | 262 | if (all == 0) |
726f6388 JA |
263 | return (1); |
264 | } | |
265 | ||
266 | /* Command is a function? */ | |
267 | func = find_function (command); | |
268 | ||
269 | if (func) | |
270 | { | |
271 | if (verbose == 1) | |
ccc6cda3 | 272 | puts ("function"); |
726f6388 JA |
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 | ||
b72432fd | 293 | if (all == 0) |
726f6388 JA |
294 | return (1); |
295 | } | |
296 | ||
297 | /* Command is a builtin? */ | |
298 | if (find_shell_builtin (command)) | |
299 | { | |
300 | if (verbose == 1) | |
ccc6cda3 | 301 | puts ("builtin"); |
726f6388 JA |
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 | ||
b72432fd | 309 | if (all == 0) |
726f6388 JA |
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 | { | |
bb70624e | 318 | f = file_status (command); |
726f6388 | 319 | if (f & FS_EXECABLE) |
28ef6c31 | 320 | { |
726f6388 | 321 | if (verbose == 1) |
ccc6cda3 | 322 | puts ("file"); |
726f6388 JA |
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); | |
28ef6c31 | 332 | } |
726f6388 JA |
333 | } |
334 | ||
b72432fd | 335 | /* If the user isn't doing "-a", then we might care about |
726f6388 | 336 | whether the file is present in our hash table. */ |
b72432fd | 337 | if (all == 0) |
726f6388 JA |
338 | { |
339 | if ((full_path = find_hashed_filename (command)) != (char *)NULL) | |
340 | { | |
341 | if (verbose == 1) | |
ccc6cda3 | 342 | puts ("file"); |
726f6388 JA |
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 | ||
d166f048 | 348 | free (full_path); |
726f6388 JA |
349 | return (1); |
350 | } | |
351 | } | |
352 | ||
353 | /* Now search through $PATH. */ | |
354 | while (1) | |
355 | { | |
b72432fd | 356 | if (all == 0) |
726f6388 JA |
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 | ||
bb70624e JA |
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 | ||
726f6388 JA |
383 | found_file++; |
384 | found = 1; | |
385 | ||
386 | if (verbose == 1) | |
ccc6cda3 | 387 | puts ("file"); |
726f6388 JA |
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 | ||
b72432fd | 396 | if (all == 0) |
726f6388 JA |
397 | break; |
398 | } | |
399 | ||
400 | return (found); | |
401 | } |