aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar ridiculousfish <corydoras@ridiculousfish.com>2015-08-08 14:52:04 -0700
committerGravatar ridiculousfish <corydoras@ridiculousfish.com>2015-08-08 14:52:04 -0700
commit3a3a9f5cc15ccfc9f171f8916c5a0470a3585319 (patch)
tree3f9674f39650e5143a35db69577f4e23b840a3a6
parentf87268e2acad39bcf27528b171bea49e50108dc2 (diff)
Add wreaddir_for_dirs function
Eliminates some stat calls, speeding up wildcard expansion
-rw-r--r--src/wildcard.cpp4
-rw-r--r--src/wutil.cpp34
-rw-r--r--src/wutil.h8
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);