From 4ef512effa8d27c743b29cba0c75a65a6eb1af50 Mon Sep 17 00:00:00 2001 From: q66 Date: Sun, 15 Apr 2018 23:23:19 +0200 Subject: [PATCH] add a range to iterate a directory --- build.cc | 2 ++ ostd/path.hh | 82 +++++++++++++++++++++++++++++++++++++++++++++++ src/path.cc | 14 ++++++++ src/posix/path.cc | 59 ++++++++++++++++++++++++++++++++++ src/win32/path.cc | 6 ++++ 5 files changed, 163 insertions(+) create mode 100644 src/path.cc create mode 100644 src/posix/path.cc create mode 100644 src/win32/path.cc diff --git a/build.cc b/build.cc index c7e27af..b13907b 100644 --- a/build.cc +++ b/build.cc @@ -14,6 +14,7 @@ #include "ostd/range.hh" #include "ostd/format.hh" #include "ostd/string.hh" +#include "ostd/path.hh" #include "ostd/filesystem.hh" #include "ostd/thread_pool.hh" #include "ostd/channel.hh" @@ -24,6 +25,7 @@ namespace fs = ostd::filesystem; /* ugly, but do not explicitly compile */ #include "src/io.cc" #include "src/process.cc" +#include "srC/path.cc" #include "src/filesystem.cc" #include "src/thread_pool.cc" #include "src/channel.cc" diff --git a/ostd/path.hh b/ostd/path.hh index b2db165..18ee659 100644 --- a/ostd/path.hh +++ b/ostd/path.hh @@ -366,6 +366,10 @@ struct path { p_path = "."; } + bool empty() const { + return (p_path == "."); + } + void swap(path &other) noexcept { p_path.swap(other.p_path); std::swap(p_fmt, other.p_fmt); @@ -689,6 +693,84 @@ namespace fs { * @{ */ +struct directory_entry { + directory_entry() {} + directory_entry(ostd::path const &p): p_path(p) {} + + ostd::path const &path() const noexcept { + return p_path; + } + + operator ostd::path const &() const noexcept { + return p_path; + } + + void clear() { + p_path.clear(); + } + + void assign(ostd::path const &p) { + p_path = p; + } + + void assign(ostd::path &&p) { + p_path = std::move(p); + } + +private: + ostd::path p_path{}; +}; + +struct directory_range: input_range { + using range_category = input_range_tag; + using value_type = directory_entry; + using reference = directory_entry const &; + using size_type = std::size_t; + + directory_range() = delete; + directory_range(path const &p) { + open(p); + } + + directory_range(directory_range const &r) noexcept: + p_current(r.p_current), p_dir(r.p_dir), + p_handle(r.p_handle), p_owned(false) + {} + + ~directory_range() { + close(); + } + + directory_range &operator=(directory_range const &r) noexcept { + close(); + p_handle = r.p_handle; + p_owned = false; + return *this; + } + + bool empty() const noexcept { + return p_current.path().empty(); + } + + void pop_front() { + read_next(); + } + + reference front() const noexcept { + return p_current; + } + +private: + void open(path const &p); + void close() noexcept; + void read_next(); + + directory_entry p_current{}; + path p_dir{}; + void *p_handle = nullptr; + bool p_owned = false; +}; + OSTD_EXPORT path cwd(); OSTD_EXPORT path home(); diff --git a/src/path.cc b/src/path.cc new file mode 100644 index 0000000..383ce24 --- /dev/null +++ b/src/path.cc @@ -0,0 +1,14 @@ +/* Decides between POSIX and Windows for path. + * + * This file is part of libostd. See COPYING.md for futher information. + */ + +#include "ostd/platform.hh" + +#if defined(OSTD_PLATFORM_WIN32) +# include "src/win32/path.cc" +#elif defined(OSTD_PLATFORM_POSIX) +# include "src/posix/path.cc" +#else +# error "Unsupported platform" +#endif diff --git a/src/posix/path.cc b/src/posix/path.cc new file mode 100644 index 0000000..8721476 --- /dev/null +++ b/src/posix/path.cc @@ -0,0 +1,59 @@ +/* Path implementation bits. + * + * This file is part of libostd. See COPYING.md for futher information. + */ + +#include +#include + +#include "ostd/path.hh" + +namespace ostd { +namespace fs { + +void directory_range::open(path const &p) { + DIR *d = opendir(p.string().data()); + if (!d) { + /* FIXME: throw */ + abort(); + } + p_dir = p; + p_handle = d; + p_owned = true; + read_next(); +} + +void directory_range::close() noexcept { + if (!p_owned) { + return; + } + closedir(static_cast(p_handle)); + p_owned = false; +} + +void directory_range::read_next() { + struct dirent d; + struct dirent *o; + DIR *dh = static_cast(p_handle); + for (;;) { + if (readdir_r(dh, &d, &o)) { + /* FIXME: throw */ + abort(); + } + if (!o) { + p_current.clear(); + return; + } + string_range nm{static_cast(o->d_name)}; + if ((nm == ".") || (nm == "..")) { + continue; + } + path p{p_dir}; + p.append(nm); + p_current.assign(std::move(p)); + break; + } +} + +} /* namesapce fs */ +} /* namespace ostd */ diff --git a/src/win32/path.cc b/src/win32/path.cc new file mode 100644 index 0000000..de9dbd8 --- /dev/null +++ b/src/win32/path.cc @@ -0,0 +1,6 @@ +/* Path implementation bits. + * + * This file is part of libostd. See COPYING.md for futher information. + */ + +#error "path doesn't work on Windows at this time"