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