2f69f6581c374393b626fa3f755f39dbcea7b9be
[platform/upstream/bash.git] / builtins / hash.def
1 This file is hash.def, from which is created hash.c.
2 It implements the builtin "hash" in Bash.
3
4 Copyright (C) 1987, 1989, 1991 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 hash.c
23
24 $BUILTIN hash
25 $FUNCTION hash_builtin
26 $SHORT_DOC hash [-r] [-p pathname] [name ...]
27 For each NAME, the full pathname of the command is determined and
28 remembered.  If the -p option is supplied, PATHNAME is used as the
29 full pathname of NAME, and no path search is performed.  The -r
30 option causes the shell to forget all remembered locations.  If no
31 arguments are given, information about remembered commands is displayed.
32 $END
33
34 #include <config.h>
35
36 #include <sys/types.h>
37 #include "../posixstat.h"
38
39 #include <stdio.h>
40
41 #if defined (HAVE_UNISTD_H)
42 #  include <unistd.h>
43 #endif
44
45 #include "../bashansi.h"
46
47 #include "../shell.h"
48 #include "../builtins.h"
49 #include "../flags.h"
50 #include "../execute_cmd.h"
51 #include "hashcom.h"
52 #include "common.h"
53 #include "bashgetopt.h"
54
55 extern int dot_found_in_search;
56 extern char *this_command_name;
57
58 static int add_hashed_command ();
59 static int print_hashed_commands ();
60
61 static int hashing_initialized = 0;
62
63 HASH_TABLE *hashed_filenames;
64
65 void
66 initialize_filename_hashing ()
67 {
68   if (hashing_initialized == 0)
69     {
70       hashed_filenames = make_hash_table (FILENAME_HASH_BUCKETS);
71       hashing_initialized = 1;
72     }
73 }
74
75 static void
76 free_filename_data (data)
77      char *data;
78 {
79   free (((PATH_DATA *)data)->path);
80   free (data);
81 }
82
83 void
84 flush_hashed_filenames ()
85 {
86   flush_hash_table (hashed_filenames, free_filename_data);
87 }
88
89 /* Remove FILENAME from the table of hashed commands. */
90 void
91 remove_hashed_filename (filename)
92      char *filename;
93 {
94   register BUCKET_CONTENTS *item;
95
96   if (hashing_enabled == 0)
97     return;
98
99   item = remove_hash_item (filename, hashed_filenames);
100   if (item)
101     {
102       if (item->data)
103         free_filename_data (item->data);
104       free (item->key);
105       free (item);
106     }
107 }
108
109 /* Print statistics on the current state of hashed commands.  If LIST is
110    not empty, then rehash (or hash in the first place) the specified
111    commands. */
112 int
113 hash_builtin (list)
114      WORD_LIST *list;
115 {
116   int expunge_hash_table, opt;
117   char *word, *pathname;
118
119   if (hashing_enabled == 0)
120     {
121       builtin_error ("hashing disabled");
122       return (EXECUTION_FAILURE);
123     }
124
125   expunge_hash_table = 0;
126   pathname = (char *)NULL;
127   reset_internal_getopt ();
128   while ((opt = internal_getopt (list, "rp:")) != -1)
129     {
130       switch (opt)
131         {
132         case 'r':
133           expunge_hash_table = 1;
134           break;
135         case 'p':
136           pathname = list_optarg;
137           break;
138         default:
139           builtin_usage ();
140           return (EX_USAGE);
141         }
142     }
143   list = loptend;
144
145   /* We want hash -r to be silent, but hash -- to print hashing info.  That
146      is the reason for the test of expunge_hash_table. */
147   if (list == 0 && expunge_hash_table == 0)
148     {
149       if (print_hashed_commands () == 0)
150         printf ("%s: hash table empty\n", this_command_name);
151
152       return (EXECUTION_SUCCESS);
153     }
154
155   if (expunge_hash_table)
156     flush_hashed_filenames ();
157
158   for (opt = EXECUTION_SUCCESS; list; list = list->next)
159     {
160       /* Add or rehash the specified commands. */
161       word = list->word->word;
162       if (pathname)
163         remember_filename (word, pathname, 0, 0);
164       else
165         {
166           if (absolute_program (word))
167             {
168               list = list->next;
169               continue;
170             }
171
172           if (add_hashed_command (word))
173             opt = EXECUTION_FAILURE;
174         }
175     }
176
177   fflush (stdout);
178
179   return (opt);
180 }
181
182 /* Place FILENAME (key) and FULL_PATHNAME (data->path) into the
183    hash table.  CHECK_DOT if non-null is for future calls to
184    find_hashed_filename (); it means that this file was found
185    in a directory in $PATH that is not an absolute pathname.
186    FOUND is the initial value for times_found. */
187 void
188 remember_filename (filename, full_pathname, check_dot, found)
189      char *filename, *full_pathname;
190      int check_dot, found;
191 {
192   register BUCKET_CONTENTS *item;
193
194   if (hashing_enabled == 0)
195     return;
196
197   item = add_hash_item (filename, hashed_filenames);
198   if (item->data)
199     free (pathdata(item)->path);
200   else
201     {
202       item->key = savestring (filename);
203       item->data = xmalloc (sizeof (PATH_DATA));
204     }
205   pathdata(item)->path = savestring (full_pathname);
206   pathdata(item)->flags = 0;
207   if (check_dot)
208     pathdata(item)->flags |= HASH_CHKDOT;
209   if (*full_pathname != '/')
210     pathdata(item)->flags |= HASH_RELPATH;
211   item->times_found = found;
212 }
213
214 static int
215 add_hashed_command (word, quiet)
216      char *word;
217      int quiet;
218 {
219   int rv;
220   char *full_path;
221
222   rv = 0;
223   if (find_function (word) == 0 && find_shell_builtin (word) == 0)
224     {
225       full_path = find_user_command (word);
226       if (full_path && executable_file (full_path))
227         remember_filename (word, full_path, dot_found_in_search, 0);
228       else
229         {
230           if (quiet == 0)
231             builtin_error ("%s: not found", word);
232           rv++;
233         }
234       if (full_path)
235         free (full_path);
236     }
237   return (rv);
238 }
239
240 /* Print information about current hashed info. */
241 static int
242 print_hashed_commands ()
243 {
244   BUCKET_CONTENTS *item_list;
245   int bucket, any_printed;
246
247   for (bucket = any_printed = 0; bucket < hashed_filenames->nbuckets; bucket++)
248     {
249       item_list = get_hash_bucket (bucket, hashed_filenames);
250       if (item_list == 0)
251         continue;
252
253       if (any_printed == 0)
254         {
255           printf ("hits\tcommand\n");
256           any_printed++;
257         }
258
259       for ( ; item_list; item_list = item_list->next)
260         printf ("%4d\t%s\n", item_list->times_found, pathdata(item_list)->path);
261
262     }
263   return (any_printed);
264 }