From 02af7e788f3fef0dbba0ba49442054fb451f5bdc Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 9 Jul 2015 12:25:47 +0200 Subject: Implement directory iteration support --- butl/filesystem | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) (limited to 'butl/filesystem') diff --git a/butl/filesystem b/butl/filesystem index 18ba48e..4d0b7ef 100644 --- a/butl/filesystem +++ b/butl/filesystem @@ -7,6 +7,14 @@ #include // mode_t +#ifndef _WIN32 +# include // DIR, struct dirent, *dir() +#endif + +#include // ptrdiff_t +#include // move() +#include + #include #include @@ -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 + #endif // BUTL_FILESYSTEM -- cgit v1.1