diff options
author | Jari Aalto <jari.aalto@cante.net> | 1997-06-05 14:59:13 +0000 |
---|---|---|
committer | Jari Aalto <jari.aalto@cante.net> | 2009-09-12 16:46:50 +0000 |
commit | d166f048818e10cf3799aa24a174fb22835f1acc (patch) | |
tree | 1ca27f9243900f8b236d0cde6a3862002aea9e19 /hashcmd.c | |
parent | ccc6cda312fea9f0468ee65b8f368e9653e1380b (diff) | |
download | bash-d166f048818e10cf3799aa24a174fb22835f1acc.tar.gz |
Imported from ../bash-2.01.tar.gz.
Diffstat (limited to 'hashcmd.c')
-rw-r--r-- | hashcmd.c | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/hashcmd.c b/hashcmd.c new file mode 100644 index 00000000..381c4756 --- /dev/null +++ b/hashcmd.c @@ -0,0 +1,191 @@ +/* hashcmd.c - functions for managing a hash table mapping command names to + full pathnames. */ + +/* Copyright (C) 1997 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + Bash is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 1, or (at your option) any later + version. + + Bash is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with Bash; see the file COPYING. If not, write to the Free Software + Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <config.h> + +#include "bashtypes.h" +#include "posixstat.h" + +#if defined (HAVE_UNISTD_H) +# include <unistd.h> +#endif + +#include "bashansi.h" + +#include "shell.h" +#include "execute_cmd.h" +#include "hashcmd.h" + +extern int hashing_enabled; + +static int hashing_initialized = 0; + +HASH_TABLE *hashed_filenames; + +void +initialize_filename_hashing () +{ + if (hashing_initialized == 0) + { + hashed_filenames = make_hash_table (FILENAME_HASH_BUCKETS); + hashing_initialized = 1; + } +} + +static void +free_filename_data (data) + char *data; +{ + free (((PATH_DATA *)data)->path); + free (data); +} + +void +flush_hashed_filenames () +{ + if (hashed_filenames) + flush_hash_table (hashed_filenames, free_filename_data); +} + +/* Remove FILENAME from the table of hashed commands. */ +void +remove_hashed_filename (filename) + char *filename; +{ + register BUCKET_CONTENTS *item; + + if (hashing_enabled == 0 || hashed_filenames == 0) + return; + + item = remove_hash_item (filename, hashed_filenames); + if (item) + { + if (item->data) + free_filename_data (item->data); + free (item->key); + free (item); + } +} + +/* Place FILENAME (key) and FULL_PATHNAME (data->path) into the + hash table. CHECK_DOT if non-null is for future calls to + find_hashed_filename (); it means that this file was found + in a directory in $PATH that is not an absolute pathname. + FOUND is the initial value for times_found. */ +void +remember_filename (filename, full_pathname, check_dot, found) + char *filename, *full_pathname; + int check_dot, found; +{ + register BUCKET_CONTENTS *item; + + if (hashing_enabled == 0) + return; + + if (hashed_filenames == 0 || hashing_initialized == 0) + initialize_filename_hashing (); + + item = add_hash_item (filename, hashed_filenames); + if (item->data) + free (pathdata(item)->path); + else + { + item->key = savestring (filename); + item->data = xmalloc (sizeof (PATH_DATA)); + } + pathdata(item)->path = savestring (full_pathname); + pathdata(item)->flags = 0; + if (check_dot) + pathdata(item)->flags |= HASH_CHKDOT; + if (*full_pathname != '/') + pathdata(item)->flags |= HASH_RELPATH; + item->times_found = found; +} + +/* Return the full pathname that FILENAME hashes to. If FILENAME + is hashed, but (data->flags & HASH_CHKDOT) is non-zero, check + ./FILENAME and return that if it is executable. This always + returns a newly-allocated string; the caller is responsible + for freeing it. */ +char * +find_hashed_filename (filename) + char *filename; +{ + register BUCKET_CONTENTS *item; + char *path, *dotted_filename, *tail; + int same; + + if (hashing_enabled == 0 || hashed_filenames == 0) + return ((char *)NULL); + + item = find_hash_item (filename, hashed_filenames); + + if (item == NULL) + return ((char *)NULL); + + /* If this filename is hashed, but `.' comes before it in the path, + see if ./filename is executable. If the hashed value is not an + absolute pathname, see if ./`hashed-value' exists. */ + path = pathdata(item)->path; + if (pathdata(item)->flags & (HASH_CHKDOT|HASH_RELPATH)) + { + tail = (pathdata(item)->flags & HASH_RELPATH) ? path : filename; + dotted_filename = xmalloc (3 + strlen (tail)); + dotted_filename[0] = '.'; dotted_filename[1] = '/'; + strcpy (dotted_filename + 2, tail); + + if (executable_file (dotted_filename)) + return (dotted_filename); + + free (dotted_filename); + +#if 0 + if (pathdata(item)->flags & HASH_RELPATH) + return ((char *)NULL); +#endif + + /* Watch out. If this file was hashed to "./filename", and + "./filename" is not executable, then return NULL. */ + + /* Since we already know "./filename" is not executable, what + we're really interested in is whether or not the `path' + portion of the hashed filename is equivalent to the current + directory, but only if it starts with a `.'. (This catches + ./. and so on.) same_file () tests general Unix file + equivalence -- same device and inode. */ + if (*path == '.') + { + same = 0; + tail = (char *)strrchr (path, '/'); + + if (tail) + { + *tail = '\0'; + same = same_file (".", path, (struct stat *)NULL, (struct stat *)NULL); + *tail = '/'; + } + + return same ? (char *)NULL : savestring (path); + } + } + + return (savestring (path)); +} |