diff options
author | ridiculousfish <corydoras@ridiculousfish.com> | 2015-08-08 14:52:04 -0700 |
---|---|---|
committer | ridiculousfish <corydoras@ridiculousfish.com> | 2015-08-08 14:52:04 -0700 |
commit | 3a3a9f5cc15ccfc9f171f8916c5a0470a3585319 (patch) | |
tree | 3f9674f39650e5143a35db69577f4e23b840a3a6 | |
parent | f87268e2acad39bcf27528b171bea49e50108dc2 (diff) |
Add wreaddir_for_dirs function
Eliminates some stat calls, speeding up wildcard expansion
-rw-r--r-- | src/wildcard.cpp | 4 | ||||
-rw-r--r-- | src/wutil.cpp | 34 | ||||
-rw-r--r-- | src/wutil.h | 8 |
3 files changed, 44 insertions, 2 deletions
diff --git a/src/wildcard.cpp b/src/wildcard.cpp index b8d30beb..3afbe84c 100644 --- a/src/wildcard.cpp +++ b/src/wildcard.cpp @@ -814,7 +814,7 @@ void wildcard_expander_t::expand_trailing_slash(const wcstring &base_dir) void wildcard_expander_t::expand_intermediate_segment(const wcstring &base_dir, DIR *base_dir_fp, const wcstring &wc_segment, const wchar_t *wc_remainder) { wcstring name_str; - while (!interrupted() && wreaddir(base_dir_fp, name_str)) + while (!interrupted() && wreaddir_for_dirs(base_dir_fp, &name_str)) { /* Note that it's critical we ignore leading dots here, else we may descend into . and .. */ if (! wildcard_match(name_str, wc_segment, true)) @@ -849,7 +849,7 @@ void wildcard_expander_t::expand_literal_intermediate_segment_with_fuzz(const wc // This only works with tab completions // Ordinary wildcard expansion should never go fuzzy wcstring name_str; - while (!interrupted() && wreaddir(base_dir_fp, name_str)) + while (!interrupted() && wreaddir_for_dirs(base_dir_fp, &name_str)) { /* Don't bother with . and .. */ if (contains(name_str, L".", L"..")) diff --git a/src/wutil.cpp b/src/wutil.cpp index b5689eec..19645042 100644 --- a/src/wutil.cpp +++ b/src/wutil.cpp @@ -115,6 +115,40 @@ bool wreaddir(DIR *dir, std::wstring &out_name) return true; } +bool wreaddir_for_dirs(DIR *dir, wcstring *out_name) +{ + struct dirent *result = NULL; + while (result == NULL) + { + struct dirent *d = readdir(dir); + if (!d) break; + +#if HAVE_STRUCT_DIRENT_D_TYPE + switch (d->d_type) + { + // These may be directories + case DT_DIR: + case DT_LNK: + case DT_UNKNOWN: + result = d; + break; + + // Nothing else can + default: + break; + } +#else + /* We can't determine if it's a directory or not, so just return it */ + result = d; +#endif + } + if (result && out_name) + { + *out_name = str2wcstring(result->d_name); + } + return result != NULL; +} + wchar_t *wgetcwd(wchar_t *buff, size_t sz) { diff --git a/src/wutil.h b/src/wutil.h index 0f97eafb..5c9a0ec2 100644 --- a/src/wutil.h +++ b/src/wutil.h @@ -95,6 +95,14 @@ bool wreaddir(DIR *dir, std::wstring &out_name); bool wreaddir_resolving(DIR *dir, const std::wstring &dir_path, std::wstring &out_name, bool *out_is_dir); /** + Like wreaddir, but skip items that are known to not be directories. + If this requires a stat (i.e. the file is a symlink), then return it. + Note that this does not guarantee that everything returned is a directory, + it's just an optimization for cases where we would check for directories anyways. +*/ +bool wreaddir_for_dirs(DIR *dir, wcstring *out_name); + +/** Wide character version of dirname() */ std::wstring wdirname(const std::wstring &path); |