d03ccb2d91bc7260c098fa4d8ccfd007531a5175
[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-2002 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 [-afptP] 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, builtins, and
41 functions, if and only if the -p flag is not also used.
42
43 The -f flag suppresses shell function lookup.
44
45 The -P flag forces a PATH search for each NAME, even if it is an alias,
46 builtin, or function, and returns the name of the disk file that would
47 be executed.
48 $END
49
50 #include <config.h>
51
52 #include "../bashtypes.h"
53 #include "posixstat.h"
54
55 #if defined (HAVE_UNISTD_H)
56 #  include <unistd.h>
57 #endif
58
59 #include <stdio.h>
60 #include "../bashansi.h"
61 #include "../bashintl.h"
62
63 #include "../shell.h"
64 #include "../findcmd.h"
65 #include "../hashcmd.h"
66
67 #if defined (ALIAS)
68 #include "../alias.h"
69 #endif /* ALIAS */
70
71 #include "common.h"
72 #include "bashgetopt.h"
73
74 extern int find_reserved_word __P((char *));
75
76 extern char *this_command_name;
77 extern int expand_aliases, posixly_correct;
78
79 /* For each word in LIST, find out what the shell is going to do with
80    it as a simple command. i.e., which file would this shell use to
81    execve, or if it is a builtin command, or an alias.  Possible flag
82    arguments:
83         -t              Returns the "type" of the object, one of
84                         `alias', `keyword', `function', `builtin',
85                         or `file'.
86
87         -p              Returns the pathname of the file if -type is
88                         a file.
89
90         -a              Returns all occurrences of words, whether they
91                         be a filename in the path, alias, function,
92                         or builtin.
93
94         -f              Suppress shell function lookup, like `command'.
95
96         -P              Force a path search even in the presence of other
97                         definitions.
98
99    Order of evaluation:
100         alias
101         keyword
102         function
103         builtin
104         file
105  */
106
107 int
108 type_builtin (list)
109      WORD_LIST *list;
110 {
111   int dflags, successful_finds, opt;
112   WORD_LIST *this;
113
114   if (list == 0)
115     return (EXECUTION_SUCCESS);
116
117   dflags = CDESC_SHORTDESC;     /* default */
118   successful_finds = 0;
119
120   /* Handle the obsolescent `-type', `-path', and `-all' by prescanning
121      the arguments and converting those options to the form that
122      internal_getopt recognizes. Converts `--type', `--path', and `--all'
123      also. THIS SHOULD REALLY GO AWAY. */
124   for (this = list; this && this->word->word[0] == '-'; this = this->next)
125     {
126       char *flag = &(this->word->word[1]);
127
128       if (STREQ (flag, "type") || STREQ (flag, "-type"))
129         {
130           this->word->word[1] = 't';
131           this->word->word[2] = '\0';
132         }
133       else if (STREQ (flag, "path") || STREQ (flag, "-path"))
134         {
135           this->word->word[1] = 'p';
136           this->word->word[2] = '\0';
137         }
138       else if (STREQ (flag, "all") || STREQ (flag, "-all"))
139         {
140           this->word->word[1] = 'a';
141           this->word->word[2] = '\0';
142         }
143     }
144
145   reset_internal_getopt ();
146   while ((opt = internal_getopt (list, "afptP")) != -1)
147     {
148       switch (opt)
149         {
150         case 'a':
151           dflags |= CDESC_ALL;
152           break;
153         case 'f':
154           dflags |= CDESC_NOFUNCS;
155           break;
156         case 'p':
157           dflags |= CDESC_PATH_ONLY;
158           dflags &= ~(CDESC_TYPE|CDESC_SHORTDESC);
159           break;
160         case 't':
161           dflags |= CDESC_TYPE;
162           dflags &= ~(CDESC_PATH_ONLY|CDESC_SHORTDESC);
163           break;
164         case 'P':       /* shorthand for type -ap */
165           dflags |= (CDESC_PATH_ONLY|CDESC_FORCE_PATH);
166           dflags &= ~(CDESC_TYPE|CDESC_SHORTDESC);
167           break;
168         default:
169           builtin_usage ();
170           return (EX_USAGE);
171         }
172     }
173   list = loptend;
174
175   while (list)
176     {
177       int found;
178
179       found = describe_command (list->word->word, dflags);
180
181       if (!found && (dflags & (CDESC_PATH_ONLY|CDESC_TYPE)) == 0)
182         sh_notfound (list->word->word);
183
184       successful_finds += found;
185       list = list->next;
186     }
187
188   fflush (stdout);
189
190   return ((successful_finds != 0) ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
191 }
192
193 /*
194  * Describe COMMAND as required by the type and command builtins.
195  *
196  * Behavior is controlled by DFLAGS.  Flag values are
197  *      CDESC_ALL       print all descriptions of a command
198  *      CDESC_SHORTDESC print the description for type and command -V
199  *      CDESC_REUSABLE  print in a format that may be reused as input
200  *      CDESC_TYPE      print the type for type -t
201  *      CDESC_PATH_ONLY print the path for type -p
202  *      CDESC_FORCE_PATH        force a path search for type -P
203  *      CDESC_NOFUNCS   skip function lookup for type -f
204  *      CDESC_ABSPATH   convert to absolute path, no ./ prefix
205  *
206  * CDESC_ALL says whether or not to look for all occurrences of COMMAND, or
207  * return after finding it once.
208  */
209 int
210 describe_command (command, dflags)
211      char *command;
212      int dflags;
213 {
214   int found, i, found_file, f, all;
215   char *full_path, *x;
216   SHELL_VAR *func;
217 #if defined (ALIAS)
218   alias_t *alias;
219 #endif
220
221   all = (dflags & CDESC_ALL) != 0;
222   found = found_file = 0;
223   full_path = (char *)NULL;
224
225 #if defined (ALIAS)
226   /* Command is an alias? */
227   if (((dflags & CDESC_FORCE_PATH) == 0) && expand_aliases && (alias = find_alias (command)))
228     {
229       if (dflags & CDESC_TYPE)
230         puts ("alias");
231       else if (dflags & CDESC_SHORTDESC)
232         printf (_("%s is aliased to `%s'\n"), command, alias->value);
233       else if (dflags & CDESC_REUSABLE)
234         {
235           x = sh_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   if (((dflags & CDESC_FORCE_PATH) == 0) && (i = find_reserved_word (command)) >= 0)
249     {
250       if (dflags & CDESC_TYPE)
251         puts ("keyword");
252       else if (dflags & CDESC_SHORTDESC)
253         printf (_("%s is a shell keyword\n"), command);
254       else if (dflags & CDESC_REUSABLE)
255         printf ("%s\n", command);
256
257       found = 1;
258
259       if (all == 0)
260         return (1);
261     }
262
263   /* Command is a function? */
264   if (((dflags & (CDESC_FORCE_PATH|CDESC_NOFUNCS)) == 0) && (func = find_function (command)))
265     {
266       if (dflags & CDESC_TYPE)
267         puts ("function");
268       else if (dflags & CDESC_SHORTDESC)
269         {
270 #define PRETTY_PRINT_FUNC 1
271           char *result;
272
273           printf (_("%s is a function\n"), command);
274
275           /* We're blowing away THE_PRINTED_COMMAND here... */
276
277           result = named_function_string (command,
278                                           (COMMAND *) function_cell (func),
279                                           PRETTY_PRINT_FUNC);
280           printf ("%s\n", result);
281 #undef PRETTY_PRINT_FUNC
282         }
283       else if (dflags & CDESC_REUSABLE)
284         printf ("%s\n", command);
285
286       found = 1;
287
288       if (all == 0)
289         return (1);
290     }
291
292   /* Command is a builtin? */
293   if (((dflags & CDESC_FORCE_PATH) == 0) && find_shell_builtin (command))
294     {
295       if (dflags & CDESC_TYPE)
296         puts ("builtin");
297       else if (dflags & CDESC_SHORTDESC)
298         printf (_("%s is a shell builtin\n"), command);
299       else if (dflags & CDESC_REUSABLE)
300         printf ("%s\n", command);
301
302       found = 1;
303
304       if (all == 0)
305         return (1);
306     }
307
308   /* Command is a disk file? */
309   /* If the command name given is already an absolute command, just
310      check to see if it is executable. */
311   if (absolute_program (command))
312     {
313       f = file_status (command);
314       if (f & FS_EXECABLE)
315         {
316           if (dflags & CDESC_TYPE)
317             puts ("file");
318           else if (dflags & CDESC_SHORTDESC)
319             printf (_("%s is %s\n"), command, command);
320           else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY))
321             printf ("%s\n", command);
322
323           /* There's no use looking in the hash table or in $PATH,
324              because they're not consulted when an absolute program
325              name is supplied. */
326           return (1);
327         }
328     }
329
330   /* If the user isn't doing "-a", then we might care about
331      whether the file is present in our hash table. */
332   if (all == 0 || (dflags & CDESC_FORCE_PATH))
333     {
334       if (full_path = phash_search (command))
335         {
336           if (dflags & CDESC_TYPE)
337             puts ("file");
338           else if (dflags & CDESC_SHORTDESC)
339             printf (_("%s is hashed (%s)\n"), command, full_path);
340           else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY))
341             printf ("%s\n", full_path);
342
343           free (full_path);
344           return (1);
345         }
346     }
347
348   /* Now search through $PATH. */
349   while (1)
350     {
351       if (all == 0)
352         full_path = find_user_command (command);
353       else
354         full_path =
355           user_command_matches (command, FS_EXEC_ONLY, found_file);
356           /* XXX - should that be FS_EXEC_PREFERRED? */
357
358       if (!full_path)
359         break;
360
361       /* If we found the command as itself by looking through $PATH, it
362          probably doesn't exist.  Check whether or not the command is an
363          executable file.  If it's not, don't report a match.  This is
364          the default posix mode behavior */
365       if (STREQ (full_path, command) || posixly_correct)
366         {
367           f = file_status (full_path);
368           if ((f & FS_EXECABLE) == 0)
369             {
370               free (full_path);
371               full_path = (char *)NULL;
372               if (all == 0)
373                 break;
374             }
375           else if (ABSPATH (full_path))
376             ;   /* placeholder; don't need to do anything yet */
377           else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY|CDESC_SHORTDESC))
378             {
379               f = MP_DOCWD | ((dflags & CDESC_ABSPATH) ? MP_RMDOT : 0);
380               full_path = sh_makepath ((char *)NULL, full_path, f);
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 }