aboutsummaryrefslogtreecommitdiff
path: root/butl/filesystem
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2015-07-09 12:25:47 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2015-07-09 12:25:47 +0200
commit02af7e788f3fef0dbba0ba49442054fb451f5bdc (patch)
tree5e0295bc0d06579cfffd0df3ad176945c9c51c79 /butl/filesystem
parent38c8f0efd8f033be8fb8278aa5d0eb704dedee55 (diff)
Implement directory iteration support
Diffstat (limited to 'butl/filesystem')
-rw-r--r--butl/filesystem119
1 files changed, 119 insertions, 0 deletions
diff --git a/butl/filesystem b/butl/filesystem
index 18ba48e..4d0b7ef 100644
--- a/butl/filesystem
+++ b/butl/filesystem
@@ -7,6 +7,14 @@
#include <sys/types.h> // mode_t
+#ifndef _WIN32
+# include <dirent.h> // DIR, struct dirent, *dir()
+#endif
+
+#include <cstddef> // ptrdiff_t
+#include <utility> // move()
+#include <iterator>
+
#include <butl/path>
#include <butl/timestamp>
@@ -65,6 +73,117 @@ namespace butl
rmfile_status
try_rmfile (const path&);
+
+ // Directory entry iteration.
+ //
+ enum class entry_type
+ {
+ unknown,
+ regular,
+ directory,
+ symlink,
+ other
+ };
+
+ class dir_entry
+ {
+ public:
+ typedef butl::path path_type;
+
+ entry_type
+ type () const;
+
+ // Symlink target type in case of the symlink, type() otherwise.
+ //
+ entry_type
+ ltype () const;
+
+ // Entry path (excluding the base). To get the full path, do
+ // base () / path ().
+ //
+ const path_type&
+ path () const {return p_;}
+
+ const dir_path&
+ base () const {return b_;}
+
+ dir_entry () = default;
+ dir_entry (entry_type t, path_type p, dir_path b)
+ : t_ (t), p_ (std::move (p)), b_ (std::move (b)) {}
+
+ private:
+ entry_type
+ type (bool link) const;
+
+ private:
+ friend class dir_iterator;
+
+ mutable entry_type t_ = entry_type::unknown; // Lazy evaluation.
+ mutable entry_type lt_ = entry_type::unknown; // Lazy evaluation.
+ path_type p_;
+ dir_path b_;
+ };
+
+ class dir_iterator
+ {
+ public:
+ typedef dir_entry value_type;
+ typedef const dir_entry* pointer;
+ typedef const dir_entry& reference;
+ typedef std::ptrdiff_t difference_type;
+ typedef std::input_iterator_tag iterator_category;
+
+ ~dir_iterator ();
+ dir_iterator () = default;
+
+ explicit
+ dir_iterator (const dir_path&);
+
+ dir_iterator (const dir_iterator&) = delete;
+ dir_iterator& operator= (const dir_iterator&) = delete;
+
+ dir_iterator (dir_iterator&& x);
+ dir_iterator& operator= (dir_iterator&&);
+
+ dir_iterator& operator++ () {next (); return *this;}
+
+ reference operator* () const {return e_;}
+ pointer operator-> () const {return &e_;}
+
+ friend bool operator== (const dir_iterator&, const dir_iterator&);
+ friend bool operator!= (const dir_iterator&, const dir_iterator&);
+
+ private:
+ void
+ next ();
+
+ private:
+ dir_entry e_;
+
+#ifndef _WIN32
+ DIR* h_ {nullptr};
+#else
+ // Check move implementation.
+ //
+# error Win32 implementation lacking
+#endif
+ };
+
+ // Range-based for loop support.
+ //
+ // for (const auto& de: dir_iterator (dir_path ("/tmp"))) ...
+ //
+ // Note that the "range" (which is the "begin" iterator), is no
+ // longer usable. In other words, don't do this:
+ //
+ // dir_iterator i (...);
+ // for (...: i) ...
+ // ++i; // Invalid.
+ //
+ inline dir_iterator begin (dir_iterator& i) {return std::move (i);}
+ inline dir_iterator end (const dir_iterator&) {return dir_iterator ();}
}
+#include <butl/filesystem.ixx>
+
#endif // BUTL_FILESYSTEM