Imported from ../bash-2.05.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, 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 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 [-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 extern char *this_command_name;
70
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:
75         -t              Returns the "type" of the object, one of
76                         `alias', `keyword', `function', `builtin',
77                         or `file'.
78
79         -p              Returns the pathname of the file if -type is
80                         a file.
81
82         -a              Returns all occurrences of words, whether they
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  */
92
93 int
94 type_builtin (list)
95      WORD_LIST *list;
96 {
97   int path_only, type_only, all, verbose;
98   int successful_finds, opt;
99   WORD_LIST *prev, *this;
100
101   if (list == 0)
102     return (EXECUTION_SUCCESS);
103
104   path_only = type_only = all = 0;
105   successful_finds = 0;
106
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] == '-'; )
112     {
113       char *flag = &(this->word->word[1]);
114
115       if (STREQ (flag, "type") || STREQ (flag, "-type"))
116         {
117           type_only = 1;
118           path_only = 0;
119         }
120       else if (STREQ (flag, "path") || STREQ (flag, "-path"))
121         {
122           path_only = 1;
123           type_only = 0;
124         }
125       else if (STREQ (flag, "all") || STREQ (flag, "-all"))
126         all = 1;
127       else
128         {
129           prev = this;
130           this = this->next;
131           continue;
132         }
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;
139       else
140         {
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:
165           builtin_usage ();
166           return (EX_USAGE);
167         }
168     }
169   list = loptend;
170
171   if (type_only)
172     verbose = 1;
173   else if (path_only == 0)
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
195   return ((successful_finds != 0) ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
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  */
210 int
211 describe_command (command, verbose, all)
212      char *command;
213      int verbose, all;
214 {
215   int found, i, found_file, f;
216   char *full_path, *x, *cwd;
217   SHELL_VAR *func;
218 #if defined (ALIAS)
219   alias_t *alias;
220 #endif
221
222   found = found_file = 0;
223   full_path = (char *)NULL;
224
225 #if defined (ALIAS)
226   /* Command is an alias? */
227   alias = find_alias (command);
228
229   if (alias)
230     {
231       if (verbose == 1)
232         puts ("alias");
233       else if (verbose == 2)
234         printf ("%s is aliased to `%s'\n", command, alias->value);
235       else if (verbose == 4)
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   i = find_reserved_word (command);
251   if (i >= 0)
252     {
253       if (verbose == 1)
254         puts ("keyword");
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
262       if (all == 0)
263         return (1);
264     }
265
266   /* Command is a function? */
267   func = find_function (command);
268
269   if (func)
270     {
271       if (verbose == 1)
272         puts ("function");
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
293       if (all == 0)
294         return (1);
295     }
296
297   /* Command is a builtin? */
298   if (find_shell_builtin (command))
299     {
300       if (verbose == 1)
301         puts ("builtin");
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
309       if (all == 0)
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     {
318       f = file_status (command);
319       if (f & FS_EXECABLE)
320         {
321           if (verbose == 1)
322             puts ("file");
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);
332         }
333     }
334
335   /* If the user isn't doing "-a", then we might care about
336      whether the file is present in our hash table. */
337   if (all == 0)
338     {
339       if ((full_path = find_hashed_filename (command)) != (char *)NULL)
340         {
341           if (verbose == 1)
342             puts ("file");
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
348           free (full_path);
349           return (1);
350         }
351     }
352
353   /* Now search through $PATH. */
354   while (1)
355     {
356       if (all == 0)
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
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
383       found_file++;
384       found = 1;
385
386       if (verbose == 1)
387         puts ("file");
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
396       if (all == 0)
397         break;
398     }
399
400   return (found);
401 }