📄 findcmd.c
字号:
/* If PATH is in the temporary environment for this command, don't use the hash table to search for the full pathname. */ path = find_variable_internal ("PATH", 1); temp_path = path && tempvar_p (path); if (temp_path == 0 && path) path = (SHELL_VAR *)NULL; /* Don't waste time trying to find hashed data for a pathname that is already completely specified or if we're using a command- specific value for PATH. */ if (path == 0 && absolute_program (pathname) == 0) hashed_file = phash_search (pathname); /* If a command found in the hash table no longer exists, we need to look for it in $PATH. Thank you Posix.2. This forces us to stat every command found in the hash table. */ if (hashed_file && (posixly_correct || check_hashed_filenames)) { st = file_status (hashed_file); if ((st & (FS_EXISTS|FS_EXECABLE)) != (FS_EXISTS|FS_EXECABLE)) { phash_remove (pathname); free (hashed_file); hashed_file = (char *)NULL; } } if (hashed_file) command = hashed_file; else if (absolute_program (pathname)) /* A command containing a slash is not looked up in PATH or saved in the hash table. */ command = savestring (pathname); else { /* If $PATH is in the temporary environment, we've already retrieved it, so don't bother trying again. */ if (temp_path) { command = find_user_command_in_path (pathname, value_cell (path), FS_EXEC_PREFERRED|FS_NODIRS); } else command = find_user_command (pathname); if (command && hashing_enabled && temp_path == 0) phash_insert ((char *)pathname, command, dot_found_in_search, 1); /* XXX fix const later */ } return (command);}char *user_command_matches (name, flags, state) const char *name; int flags, state;{ register int i; int path_index, name_len; char *path_list, *path_element, *match; struct stat dotinfo; static char **match_list = NULL; static int match_list_size = 0; static int match_index = 0; if (state == 0) { /* Create the list of matches. */ if (match_list == 0) { match_list_size = 5; match_list = strvec_create (match_list_size); } /* Clear out the old match list. */ for (i = 0; i < match_list_size; i++) match_list[i] = 0; /* We haven't found any files yet. */ match_index = 0; if (absolute_program (name)) { match_list[0] = find_absolute_program (name, flags); match_list[1] = (char *)NULL; path_list = (char *)NULL; } else { name_len = strlen (name); file_to_lose_on = (char *)NULL; dot_found_in_search = 0; stat (".", &dotinfo); path_list = get_string_value ("PATH"); path_index = 0; } while (path_list && path_list[path_index]) { path_element = get_next_path_element (path_list, &path_index); if (path_element == 0) break; match = find_in_path_element (name, path_element, flags, name_len, &dotinfo); free (path_element); if (match == 0) continue; if (match_index + 1 == match_list_size) { match_list_size += 10; match_list = strvec_resize (match_list, (match_list_size + 1)); } match_list[match_index++] = match; match_list[match_index] = (char *)NULL; FREE (file_to_lose_on); file_to_lose_on = (char *)NULL; } /* We haven't returned any strings yet. */ match_index = 0; } match = match_list[match_index]; if (match) match_index++; return (match);}static char *find_absolute_program (name, flags) const char *name; int flags;{ int st; st = file_status (name); /* If the file doesn't exist, quit now. */ if ((st & FS_EXISTS) == 0) return ((char *)NULL); /* If we only care about whether the file exists or not, return this filename. Otherwise, maybe we care about whether this file is executable. If it is, and that is what we want, return it. */ if ((flags & FS_EXISTS) || ((flags & FS_EXEC_ONLY) && (st & FS_EXECABLE))) return (savestring (name)); return (NULL);}static char *find_in_path_element (name, path, flags, name_len, dotinfop) const char *name; char *path; int flags, name_len; struct stat *dotinfop;{ int status; char *full_path, *xpath; xpath = (*path == '~') ? bash_tilde_expand (path, 0) : path; /* Remember the location of "." in the path, in all its forms (as long as they begin with a `.', e.g. `./.') */ if (dot_found_in_search == 0 && *xpath == '.') dot_found_in_search = same_file (".", xpath, dotinfop, (struct stat *)NULL); full_path = sh_makepath (xpath, name, 0); status = file_status (full_path); if (xpath != path) free (xpath); if ((status & FS_EXISTS) == 0) { free (full_path); return ((char *)NULL); } /* The file exists. If the caller simply wants the first file, here it is. */ if (flags & FS_EXISTS) return (full_path); /* If we have a readable file, and the caller wants a readable file, this is it. */ if ((flags & FS_READABLE) && (status & FS_READABLE)) return (full_path); /* If the file is executable, then it satisfies the cases of EXEC_ONLY and EXEC_PREFERRED. Return this file unconditionally. */ if ((status & FS_EXECABLE) && (flags & (FS_EXEC_ONLY|FS_EXEC_PREFERRED)) && (((flags & FS_NODIRS) == 0) || ((status & FS_DIRECTORY) == 0))) { FREE (file_to_lose_on); file_to_lose_on = (char *)NULL; return (full_path); } /* The file is not executable, but it does exist. If we prefer an executable, then remember this one if it is the first one we have found. */ if ((flags & FS_EXEC_PREFERRED) && file_to_lose_on == 0) file_to_lose_on = savestring (full_path); /* If we want only executable files, or we don't want directories and this file is a directory, or we want a readable file and this file isn't readable, fail. */ if ((flags & (FS_EXEC_ONLY|FS_EXEC_PREFERRED)) || ((flags & FS_NODIRS) && (status & FS_DIRECTORY)) || ((flags & FS_READABLE) && (status & FS_READABLE) == 0)) { free (full_path); return ((char *)NULL); } else return (full_path);}/* This does the dirty work for find_user_command_internal () and user_command_matches (). NAME is the name of the file to search for. PATH_LIST is a colon separated list of directories to search. FLAGS contains bit fields which control the files which are eligible. Some values are: FS_EXEC_ONLY: The file must be an executable to be found. FS_EXEC_PREFERRED: If we can't find an executable, then the the first file matching NAME will do. FS_EXISTS: The first file found will do. FS_NODIRS: Don't find any directories.*/static char *find_user_command_in_path (name, path_list, flags) const char *name; char *path_list; int flags;{ char *full_path, *path; int path_index, name_len; struct stat dotinfo; /* We haven't started looking, so we certainly haven't seen a `.' as the directory path yet. */ dot_found_in_search = 0; if (absolute_program (name)) { full_path = find_absolute_program (name, flags); return (full_path); } if (path_list == 0 || *path_list == '\0') return (savestring (name)); /* XXX */ file_to_lose_on = (char *)NULL; name_len = strlen (name); stat (".", &dotinfo); path_index = 0; while (path_list[path_index]) { /* Allow the user to interrupt out of a lengthy path search. */ QUIT; path = get_next_path_element (path_list, &path_index); if (path == 0) break; /* Side effects: sets dot_found_in_search, possibly sets file_to_lose_on. */ full_path = find_in_path_element (name, path, flags, name_len, &dotinfo); free (path); /* This should really be in find_in_path_element, but there isn't the right combination of flags. */ if (full_path && is_directory (full_path)) { free (full_path); continue; } if (full_path) { FREE (file_to_lose_on); return (full_path); } } /* We didn't find exactly what the user was looking for. Return the contents of FILE_TO_LOSE_ON which is NULL when the search required an executable, or non-NULL if a file was found and the search would accept a non-executable as a last resort. If the caller specified FS_NODIRS, and file_to_lose_on is a directory, return NULL. */ if (file_to_lose_on && (flags & FS_NODIRS) && is_directory (file_to_lose_on)) { free (file_to_lose_on); file_to_lose_on = (char *)NULL; } return (file_to_lose_on);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -