Imported from ../bash-2.03.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 1, 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, 675 Mass Ave, Cambridge, MA 02139, 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 /* For each word in LIST, find out what the shell is going to do with
70    it as a simple command. i.e., which file would this shell use to
71    execve, or if it is a builtin command, or an alias.  Possible flag
72    arguments:
73         -t              Returns the "type" of the object, one of
74                         `alias', `keyword', `function', `builtin',
75                         or `file'.
76
77         -p              Returns the pathname of the file if -type is
78                         a file.
79
80         -a              Returns all occurrences of words, whether they
81                         be a filename in the path, alias, function,
82                         or builtin.
83    Order of evaluation:
84         alias
85         keyword
86         function
87         builtin
88         file
89  */
90
91 int
92 type_builtin (list)
93      WORD_LIST *list;
94 {
95   int path_only, type_only, all, verbose;
96   int successful_finds, opt;
97   WORD_LIST *prev, *this;
98
99   if (list == 0)
100     return (EXECUTION_SUCCESS);
101
102   path_only = type_only = all = 0;
103   successful_finds = 0;
104
105   /* Handle the obsolescent `-type', `-path', and `-all' by prescanning
106      the arguments and removing those options from the list before calling
107      internal_getopt.  Recognize `--type', `--path', and `--all' also.
108      THIS SHOULD REALLY GO AWAY. */
109   for (this = list; this && this->word->word[0] == '-'; )
110     {
111       char *flag = &(this->word->word[1]);
112
113       if (STREQ (flag, "type") || STREQ (flag, "-type"))
114         {
115           type_only = 1;
116           path_only = 0;
117         }
118       else if (STREQ (flag, "path") || STREQ (flag, "-path"))
119         {
120           path_only = 1;
121           type_only = 0;
122         }
123       else if (STREQ (flag, "all") || STREQ (flag, "-all"))
124         all = 1;
125       else
126         {
127           prev = this;
128           this = this->next;
129           continue;
130         }
131
132       /* We found a long option; remove it from the argument list.  Don't
133          free it if it's the head of the argument list, though -- the
134          argument list will be freed by the caller. */
135       if (this == list)
136         this = list = list->next;
137       else
138         {
139           prev->next = this->next;
140           this->next = (WORD_LIST *)NULL;
141           dispose_words (this);
142           this = prev->next;
143         }
144     }
145
146   reset_internal_getopt ();
147   while ((opt = internal_getopt (list, "apt")) != -1)
148     {
149       switch (opt)
150         {
151         case 't':
152           type_only = 1;
153           path_only = 0;
154           break;
155         case 'p':
156           path_only = 1;
157           type_only = 0;
158           break;
159         case 'a':
160           all = 1;
161           break;
162         default:
163           builtin_usage ();
164           return (EX_USAGE);
165         }
166     }
167   list = loptend;
168
169   if (type_only)
170     verbose = 1;
171   else if (path_only == 0)
172     verbose = 2;
173   else if (path_only)
174     verbose = 3;
175   else
176     verbose = 0;
177
178   while (list)
179     {
180       int found;
181
182       found = describe_command (list->word->word, verbose, all);
183
184       if (!found && !path_only && !type_only)
185         builtin_error ("%s: not found", list->word->word);
186
187       successful_finds += found;
188       list = list->next;
189     }
190
191   fflush (stdout);
192
193   return ((successful_finds != 0) ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
194 }
195
196 /*
197  * Describe COMMAND as required by the type builtin.
198  *
199  * If VERBOSE == 0, don't print anything
200  * If VERBOSE == 1, print short description as for `type -t'
201  * If VERBOSE == 2, print long description as for `type' and `command -V'
202  * If VERBOSE == 3, print path name only for disk files
203  * If VERBOSE == 4, print string used to invoke COMMAND, for `command -v'
204  *
205  * ALL says whether or not to look for all occurrences of COMMAND, or
206  * return after finding it once.
207  */
208 int
209 describe_command (command, verbose, all)
210      char *command;
211      int verbose, all;
212 {
213   int found, i, found_file;
214   char *full_path;
215   SHELL_VAR *func;
216 #if defined (ALIAS)
217   alias_t *alias;
218 #endif
219
220   found = found_file = 0;
221   full_path = (char *)NULL;
222
223 #if defined (ALIAS)
224   /* Command is an alias? */
225   alias = find_alias (command);
226
227   if (alias)
228     {
229       if (verbose == 1)
230         puts ("alias");
231       else if (verbose == 2)
232         printf ("%s is aliased to `%s'\n", command, alias->value);
233       else if (verbose == 4)
234         {
235           char *x = 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   i = find_reserved_word (command);
249   if (i >= 0)
250     {
251       if (verbose == 1)
252         puts ("keyword");
253       else if (verbose == 2)
254         printf ("%s is a shell keyword\n", command);
255       else if (verbose == 4)
256         printf ("%s\n", command);
257
258       found = 1;
259
260       if (all == 0)
261         return (1);
262     }
263
264   /* Command is a function? */
265   func = find_function (command);
266
267   if (func)
268     {
269       if (verbose == 1)
270         puts ("function");
271       else if (verbose == 2)
272         {
273 #define PRETTY_PRINT_FUNC 1
274           char *result;
275
276           printf ("%s is a function\n", command);
277
278           /* We're blowing away THE_PRINTED_COMMAND here... */
279
280           result = named_function_string (command,
281                                           (COMMAND *) function_cell (func),
282                                           PRETTY_PRINT_FUNC);
283           printf ("%s\n", result);
284 #undef PRETTY_PRINT_FUNC
285         }
286       else if (verbose == 4)
287         printf ("%s\n", command);
288
289       found = 1;
290
291       if (all == 0)
292         return (1);
293     }
294
295   /* Command is a builtin? */
296   if (find_shell_builtin (command))
297     {
298       if (verbose == 1)
299         puts ("builtin");
300       else if (verbose == 2)
301         printf ("%s is a shell builtin\n", command);
302       else if (verbose == 4)
303         printf ("%s\n", command);
304
305       found = 1;
306
307       if (all == 0)
308         return (1);
309     }
310
311   /* Command is a disk file? */
312   /* If the command name given is already an absolute command, just
313      check to see if it is executable. */
314   if (absolute_program (command))
315     {
316       int f = file_status (command);
317       if (f & FS_EXECABLE)
318         {
319           if (verbose == 1)
320             puts ("file");
321           else if (verbose == 2)
322             printf ("%s is %s\n", command, command);
323           else if (verbose == 3 || verbose == 4)
324             printf ("%s\n", command);
325
326           /* There's no use looking in the hash table or in $PATH,
327              because they're not consulted when an absolute program
328              name is supplied. */
329           return (1);
330         }
331     }
332
333   /* If the user isn't doing "-a", then we might care about
334      whether the file is present in our hash table. */
335   if (all == 0)
336     {
337       if ((full_path = find_hashed_filename (command)) != (char *)NULL)
338         {
339           if (verbose == 1)
340             puts ("file");
341           else if (verbose == 2)
342             printf ("%s is hashed (%s)\n", command, full_path);
343           else if (verbose == 3 || verbose == 4)
344             printf ("%s\n", full_path);
345
346           free (full_path);
347           return (1);
348         }
349     }
350
351   /* Now search through $PATH. */
352   while (1)
353     {
354       if (all == 0)
355         full_path = find_user_command (command);
356       else
357         full_path =
358           user_command_matches (command, FS_EXEC_ONLY, found_file);
359           /* XXX - should that be FS_EXEC_PREFERRED? */
360
361       if (!full_path)
362         break;
363
364       found_file++;
365       found = 1;
366
367       if (verbose == 1)
368         puts ("file");
369       else if (verbose == 2)
370         printf ("%s is %s\n", command, full_path);
371       else if (verbose == 3 || verbose == 4)
372         printf ("%s\n", full_path);
373
374       free (full_path);
375       full_path = (char *)NULL;
376
377       if (all == 0)
378         break;
379     }
380
381   return (found);
382 }