Bash-4.3 distribution sources and documentation
[platform/upstream/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-2011 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
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 Bash is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Bash.  If not, see <http://www.gnu.org/licenses/>.
20
21 $PRODUCES type.c
22
23 $BUILTIN type
24 $FUNCTION type_builtin
25 $SHORT_DOC type [-afptP] name [name ...]
26 Display information about command type.
27
28 For each NAME, indicate how it would be interpreted if used as a
29 command name.
30
31 Options:
32   -a    display all locations containing an executable named NAME;
33         includes aliases, builtins, and functions, if and only if
34         the `-p' option is not also used
35   -f    suppress shell function lookup
36   -P    force a PATH search for each NAME, even if it is an alias,
37         builtin, or function, and returns the name of the disk file
38         that would be executed
39   -p    returns either the name of the disk file that would be executed,
40         or nothing if `type -t NAME' would not return `file'.
41   -t    output a single word which is one of `alias', `keyword',
42         `function', `builtin', `file' or `', if NAME is an alias, shell
43         reserved word, shell function, shell builtin, disk file, or not 
44         found, respectively
45
46 Arguments:
47   NAME  Command name to be interpreted.
48
49 Exit Status:
50 Returns success if all of the NAMEs are found; fails if any are not found.
51 $END
52
53 #include <config.h>
54
55 #include "../bashtypes.h"
56 #include "posixstat.h"
57
58 #if defined (HAVE_UNISTD_H)
59 #  include <unistd.h>
60 #endif
61
62 #include <stdio.h>
63 #include "../bashansi.h"
64 #include "../bashintl.h"
65
66 #include "../shell.h"
67 #include "../findcmd.h"
68 #include "../hashcmd.h"
69
70 #if defined (ALIAS)
71 #include "../alias.h"
72 #endif /* ALIAS */
73
74 #include "common.h"
75 #include "bashgetopt.h"
76
77 extern int find_reserved_word __P((char *));
78
79 extern char *this_command_name;
80 extern int expand_aliases, posixly_correct;
81
82 /* For each word in LIST, find out what the shell is going to do with
83    it as a simple command. i.e., which file would this shell use to
84    execve, or if it is a builtin command, or an alias.  Possible flag
85    arguments:
86         -t              Returns the "type" of the object, one of
87                         `alias', `keyword', `function', `builtin',
88                         or `file'.
89
90         -p              Returns the pathname of the file if -type is
91                         a file.
92
93         -a              Returns all occurrences of words, whether they
94                         be a filename in the path, alias, function,
95                         or builtin.
96
97         -f              Suppress shell function lookup, like `command'.
98
99         -P              Force a path search even in the presence of other
100                         definitions.
101
102    Order of evaluation:
103         alias
104         keyword
105         function
106         builtin
107         file
108  */
109
110 int
111 type_builtin (list)
112      WORD_LIST *list;
113 {
114   int dflags, any_failed, opt;
115   WORD_LIST *this;
116
117   if (list == 0)
118     return (EXECUTION_SUCCESS);
119
120   dflags = CDESC_SHORTDESC;     /* default */
121   any_failed = 0;
122
123   /* Handle the obsolescent `-type', `-path', and `-all' by prescanning
124      the arguments and converting those options to the form that
125      internal_getopt recognizes. Converts `--type', `--path', and `--all'
126      also. THIS SHOULD REALLY GO AWAY. */
127   for (this = list; this && this->word->word[0] == '-'; this = this->next)
128     {
129       char *flag = &(this->word->word[1]);
130
131       if (STREQ (flag, "type") || STREQ (flag, "-type"))
132         {
133           this->word->word[1] = 't';
134           this->word->word[2] = '\0';
135         }
136       else if (STREQ (flag, "path") || STREQ (flag, "-path"))
137         {
138           this->word->word[1] = 'p';
139           this->word->word[2] = '\0';
140         }
141       else if (STREQ (flag, "all") || STREQ (flag, "-all"))
142         {
143           this->word->word[1] = 'a';
144           this->word->word[2] = '\0';
145         }
146     }
147
148   reset_internal_getopt ();
149   while ((opt = internal_getopt (list, "afptP")) != -1)
150     {
151       switch (opt)
152         {
153         case 'a':
154           dflags |= CDESC_ALL;
155           break;
156         case 'f':
157           dflags |= CDESC_NOFUNCS;
158           break;
159         case 'p':
160           dflags |= CDESC_PATH_ONLY;
161           dflags &= ~(CDESC_TYPE|CDESC_SHORTDESC);
162           break;
163         case 't':
164           dflags |= CDESC_TYPE;
165           dflags &= ~(CDESC_PATH_ONLY|CDESC_SHORTDESC);
166           break;
167         case 'P':       /* shorthand for type -ap */
168           dflags |= (CDESC_PATH_ONLY|CDESC_FORCE_PATH);
169           dflags &= ~(CDESC_TYPE|CDESC_SHORTDESC);
170           break;
171         default:
172           builtin_usage ();
173           return (EX_USAGE);
174         }
175     }
176   list = loptend;
177
178   while (list)
179     {
180       int found;
181
182       found = describe_command (list->word->word, dflags);
183
184       if (!found && (dflags & (CDESC_PATH_ONLY|CDESC_TYPE)) == 0)
185         sh_notfound (list->word->word);
186
187       any_failed += found == 0;
188       list = list->next;
189     }
190
191   opt = (any_failed == 0) ? EXECUTION_SUCCESS : EXECUTION_FAILURE;
192   return (sh_chkwrite (opt));
193 }
194
195 /*
196  * Describe COMMAND as required by the type and command builtins.
197  *
198  * Behavior is controlled by DFLAGS.  Flag values are
199  *      CDESC_ALL       print all descriptions of a command
200  *      CDESC_SHORTDESC print the description for type and command -V
201  *      CDESC_REUSABLE  print in a format that may be reused as input
202  *      CDESC_TYPE      print the type for type -t
203  *      CDESC_PATH_ONLY print the path for type -p
204  *      CDESC_FORCE_PATH        force a path search for type -P
205  *      CDESC_NOFUNCS   skip function lookup for type -f
206  *      CDESC_ABSPATH   convert to absolute path, no ./ prefix
207  *
208  * CDESC_ALL says whether or not to look for all occurrences of COMMAND, or
209  * return after finding it once.
210  */
211 int
212 describe_command (command, dflags)
213      char *command;
214      int dflags;
215 {
216   int found, i, found_file, f, all;
217   char *full_path, *x;
218   SHELL_VAR *func;
219 #if defined (ALIAS)
220   alias_t *alias;
221 #endif
222
223   all = (dflags & CDESC_ALL) != 0;
224   found = found_file = 0;
225   full_path = (char *)NULL;
226
227 #if defined (ALIAS)
228   /* Command is an alias? */
229   if (((dflags & CDESC_FORCE_PATH) == 0) && expand_aliases && (alias = find_alias (command)))
230     {
231       if (dflags & CDESC_TYPE)
232         puts ("alias");
233       else if (dflags & CDESC_SHORTDESC)
234         printf (_("%s is aliased to `%s'\n"), command, alias->value);
235       else if (dflags & CDESC_REUSABLE)
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   if (((dflags & CDESC_FORCE_PATH) == 0) && (i = find_reserved_word (command)) >= 0)
251     {
252       if (dflags & CDESC_TYPE)
253         puts ("keyword");
254       else if (dflags & CDESC_SHORTDESC)
255         printf (_("%s is a shell keyword\n"), command);
256       else if (dflags & CDESC_REUSABLE)
257         printf ("%s\n", command);
258
259       found = 1;
260
261       if (all == 0)
262         return (1);
263     }
264
265   /* Command is a function? */
266   if (((dflags & (CDESC_FORCE_PATH|CDESC_NOFUNCS)) == 0) && (func = find_function (command)))
267     {
268       if (dflags & CDESC_TYPE)
269         puts ("function");
270       else if (dflags & CDESC_SHORTDESC)
271         {
272           char *result;
273
274           printf (_("%s is a function\n"), command);
275
276           /* We're blowing away THE_PRINTED_COMMAND here... */
277
278           result = named_function_string (command, function_cell (func), FUNC_MULTILINE|FUNC_EXTERNAL);
279           printf ("%s\n", result);
280         }
281       else if (dflags & CDESC_REUSABLE)
282         printf ("%s\n", command);
283
284       found = 1;
285
286       if (all == 0)
287         return (1);
288     }
289
290   /* Command is a builtin? */
291   if (((dflags & CDESC_FORCE_PATH) == 0) && find_shell_builtin (command))
292     {
293       if (dflags & CDESC_TYPE)
294         puts ("builtin");
295       else if (dflags & CDESC_SHORTDESC)
296         printf (_("%s is a shell builtin\n"), command);
297       else if (dflags & CDESC_REUSABLE)
298         printf ("%s\n", command);
299
300       found = 1;
301
302       if (all == 0)
303         return (1);
304     }
305
306   /* Command is a disk file? */
307   /* If the command name given is already an absolute command, just
308      check to see if it is executable. */
309   if (absolute_program (command))
310     {
311       f = file_status (command);
312       if (f & FS_EXECABLE)
313         {
314           if (dflags & CDESC_TYPE)
315             puts ("file");
316           else if (dflags & CDESC_SHORTDESC)
317             printf (_("%s is %s\n"), command, command);
318           else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY))
319             printf ("%s\n", command);
320
321           /* There's no use looking in the hash table or in $PATH,
322              because they're not consulted when an absolute program
323              name is supplied. */
324           return (1);
325         }
326     }
327
328   /* If the user isn't doing "-a", then we might care about
329      whether the file is present in our hash table. */
330   if (all == 0 || (dflags & CDESC_FORCE_PATH))
331     {
332       if (full_path = phash_search (command))
333         {
334           if (dflags & CDESC_TYPE)
335             puts ("file");
336           else if (dflags & CDESC_SHORTDESC)
337             printf (_("%s is hashed (%s)\n"), command, full_path);
338           else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY))
339             printf ("%s\n", full_path);
340
341           free (full_path);
342           return (1);
343         }
344     }
345
346   /* Now search through $PATH. */
347   while (1)
348     {
349       if (all == 0)
350         full_path = find_user_command (command);
351       else
352         full_path =
353           user_command_matches (command, FS_EXEC_ONLY, found_file);
354           /* XXX - should that be FS_EXEC_PREFERRED? */
355
356       if (full_path == 0)
357         break;
358
359       /* If we found the command as itself by looking through $PATH, it
360          probably doesn't exist.  Check whether or not the command is an
361          executable file.  If it's not, don't report a match.  This is
362          the default posix mode behavior */
363       if (STREQ (full_path, command) || posixly_correct)
364         {
365           f = file_status (full_path);
366           if ((f & FS_EXECABLE) == 0)
367             {
368               free (full_path);
369               full_path = (char *)NULL;
370               if (all == 0)
371                 break;
372             }
373           else if (ABSPATH (full_path))
374             ;   /* placeholder; don't need to do anything yet */
375           else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY|CDESC_SHORTDESC))
376             {
377               f = MP_DOCWD | ((dflags & CDESC_ABSPATH) ? MP_RMDOT : 0);
378               x = sh_makepath ((char *)NULL, full_path, f);
379               free (full_path);
380               full_path = x;
381             }
382         }
383       /* If we require a full path and don't have one, make one */
384       else if ((dflags & CDESC_ABSPATH) && ABSPATH (full_path) == 0)
385         full_path = sh_makepath ((char *)NULL, full_path, MP_DOCWD|MP_RMDOT);
386
387       found_file++;
388       found = 1;
389
390       if (dflags & CDESC_TYPE)
391         puts ("file");
392       else if (dflags & CDESC_SHORTDESC)
393         printf (_("%s is %s\n"), command, full_path);
394       else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY))
395         printf ("%s\n", full_path);
396
397       free (full_path);
398       full_path = (char *)NULL;
399
400       if (all == 0)
401         break;
402     }
403
404   return (found);
405 }