diff --git a/ostd/path.hh b/ostd/path.hh index c883240..b9f2282 100644 --- a/ostd/path.hh +++ b/ostd/path.hh @@ -1759,54 +1759,6 @@ private: file_mode p_type{}; }; -namespace detail { - struct OSTD_EXPORT dir_range_impl { - void open(path const &p); - void close() noexcept; - void read_next(); - - bool empty() const noexcept { - return p_current.path().empty(); - } - - directory_entry const &front() const noexcept { - return p_current; - } - - ~dir_range_impl() { - close(); - } - - directory_entry p_current{}; - path p_dir{}; - void *p_handle = nullptr; - }; - - struct OSTD_EXPORT rdir_range_impl { - using hstack = std::stack>; - - void open(path const &p); - void close() noexcept; - void read_next(); - - bool empty() const noexcept { - return p_current.path().empty(); - } - - directory_entry const &front() const noexcept { - return p_current; - } - - ~rdir_range_impl() { - close(); - } - - directory_entry p_current{}; - path p_dir{}; - hstack p_handles{}; - }; -} - /** @brief A simple range for traversal of a directory. * * The range is an ostd::input_range_path, so it is only suitable for @@ -1821,7 +1773,7 @@ namespace detail { * also not defined whether entries added to the directory during * iteration will be represented in the range. **/ -struct directory_range: input_range { +struct OSTD_EXPORT directory_range: input_range { using range_category = input_range_tag; using value_type = directory_entry; using reference = directory_entry const &; @@ -1835,16 +1787,10 @@ struct directory_range: input_range { * * @throws fs::fs_error */ - directory_range(path const &p): - p_impl{std::make_shared()} - { - p_impl->open(p); - } + directory_range(path const &p); /** @brief Checks if there are any entries in the range. */ - bool empty() const noexcept { - return p_impl->empty(); - } + bool empty() const noexcept; /** @brief Pops out the current entry and retrieves the next one. * @@ -1852,14 +1798,10 @@ struct directory_range: input_range { * * @throws fs::fs_error */ - void pop_front() { - p_impl->read_next(); - } + void pop_front(); /** @brief Retrieves the current entry. */ - reference front() const noexcept { - return p_impl->front(); - } + reference front() const noexcept; private: std::shared_ptr p_impl; @@ -1872,7 +1814,9 @@ private: * a directory is still undefined, but the range does guarantee that if * th entry is a directory, it will be listed before its contents. */ -struct recursive_directory_range: input_range { +struct OSTD_EXPORT recursive_directory_range: + input_range +{ using range_category = input_range_tag; using value_type = directory_entry; using reference = directory_entry const &; @@ -1886,16 +1830,10 @@ struct recursive_directory_range: input_range { * * @throws fs::fs_error */ - recursive_directory_range(path const &p): - p_impl{std::make_shared()} - { - p_impl->open(p); - } + recursive_directory_range(path const &p); /** @brief Checks if there are any entries in the range. */ - bool empty() const noexcept { - return p_impl->empty(); - } + bool empty() const noexcept; /** @brief Pops out the current entry and retrieves the next one. * @@ -1903,14 +1841,10 @@ struct recursive_directory_range: input_range { * * @throws fs::fs_error */ - void pop_front() { - p_impl->read_next(); - } + void pop_front(); /** @brief Retrieves the current entry. */ - reference front() const noexcept { - return p_impl->front(); - } + reference front() const noexcept; private: std::shared_ptr p_impl; diff --git a/src/path.cc b/src/path.cc index 6222761..47ed39c 100644 --- a/src/path.cc +++ b/src/path.cc @@ -7,12 +7,14 @@ #include "ostd/platform.hh" -#if defined(OSTD_PLATFORM_WIN32) -# include "src/win32/path.cc" -#elif defined(OSTD_PLATFORM_POSIX) +/* we don't have a native implementation for Windows right now, but a + * platform independent generic fallback is available, depending on the + * native C++ std::filesystem module + */ +#if defined(OSTD_PLATFORM_POSIX) # include "src/posix/path.cc" #else -# error "Unsupported platform" +# include "src/any/path.cc" #endif namespace ostd { diff --git a/src/posix/path.cc b/src/posix/path.cc index cf637c6..8ef5e68 100644 --- a/src/posix/path.cc +++ b/src/posix/path.cc @@ -200,87 +200,121 @@ static void dir_read_next( } } -/* dir range */ - -OSTD_EXPORT void dir_range_impl::open(path const &p) { - DIR *d = opendir(p.string().data()); - if (!d) { - throw fs_error{"opendir failure", p, errno_ec()}; - } - p_dir = p; - p_handle = d; - read_next(); -} - -OSTD_EXPORT void dir_range_impl::close() noexcept { - closedir(static_cast(p_handle)); -} - -OSTD_EXPORT void dir_range_impl::read_next() { - path cur; - file_mode tp; - dir_read_next(static_cast(p_handle), cur, tp, p_dir); - p_current = directory_entry{std::move(cur), tp}; -} - -/* recursive dir range */ - -OSTD_EXPORT void rdir_range_impl::open(path const &p) { - DIR *d = opendir(p.string().data()); - if (!d) { - throw fs_error{"opendir failure", p, errno_ec()}; - } - p_dir = p; - p_handles.push(d); - read_next(); -} - -OSTD_EXPORT void rdir_range_impl::close() noexcept { - while (!p_handles.empty()) { - closedir(static_cast(p_handles.top())); - p_handles.pop(); - } -} - -OSTD_EXPORT void rdir_range_impl::read_next() { - if (p_handles.empty()) { - return; - } - path curd; - file_mode tp; - /* can't reuse info from dirent because we need to expand symlinks */ - if (p_current.is_directory()) { - /* directory, recurse into it and if it contains stuff, return */ - DIR *nd = opendir(p_current.path().string().data()); - if (!nd) { - throw fs_error{"opendir failure", p_current, errno_ec()}; +struct dir_range_impl { + void open(path const &p) { + DIR *d = opendir(p.string().data()); + if (!d) { + throw fs_error{"opendir failure", p, errno_ec()}; } - directory_entry based = p_current; - dir_read_next(nd, curd, tp, based); - if (!curd.empty()) { - p_dir = based; - p_handles.push(nd); - p_current = directory_entry{std::move(curd), tp}; + p_dir = p; + p_handle = d; + read_next(); + } + + void close() noexcept { + closedir(static_cast(p_handle)); + } + + void read_next() { + path cur; + file_mode tp; + dir_read_next(static_cast(p_handle), cur, tp, p_dir); + p_current = directory_entry{std::move(cur), tp}; + } + + bool empty() const noexcept { + return p_current.path().empty(); + } + + directory_entry const &front() const noexcept { + return p_current; + } + + ~dir_range_impl() { + close(); + } + + directory_entry p_current{}; + path p_dir{}; + void *p_handle = nullptr; +}; + +struct rdir_range_impl { + using hstack = std::stack>; + + void open(path const &p) { + DIR *d = opendir(p.string().data()); + if (!d) { + throw fs_error{"opendir failure", p, errno_ec()}; + } + p_dir = p; + p_handles.push(d); + read_next(); + } + + void close() noexcept { + while (!p_handles.empty()) { + closedir(static_cast(p_handles.top())); + p_handles.pop(); + } + } + + void read_next() { + if (p_handles.empty()) { return; - } else { - closedir(nd); + } + path curd; + file_mode tp; + /* can't reuse info from dirent because we need to expand symlinks */ + if (p_current.is_directory()) { + /* directory, recurse into it and if it contains stuff, return */ + DIR *nd = opendir(p_current.path().string().data()); + if (!nd) { + throw fs_error{"opendir failure", p_current, errno_ec()}; + } + directory_entry based = p_current; + dir_read_next(nd, curd, tp, based); + if (!curd.empty()) { + p_dir = based; + p_handles.push(nd); + p_current = directory_entry{std::move(curd), tp}; + return; + } else { + closedir(nd); + } + } + /* didn't recurse into a directory, go to next file */ + dir_read_next(static_cast(p_handles.top()), curd, tp, p_dir); + p_current = directory_entry{std::move(curd), tp}; + /* end of dir, pop while at it */ + if (p_current.path().empty()) { + closedir(static_cast(p_handles.top())); + p_handles.pop(); + if (!p_handles.empty()) { + /* got back to another dir, read next so it's valid */ + p_dir.remove_name(); + dir_read_next(static_cast(p_handles.top()), curd, tp, p_dir); + p_current = directory_entry{std::move(curd), tp}; + } } } - /* didn't recurse into a directory, go to next file */ - dir_read_next(static_cast(p_handles.top()), curd, tp, p_dir); - p_current = directory_entry{std::move(curd), tp}; - /* end of dir, pop while at it */ - if (p_current.path().empty()) { - closedir(static_cast(p_handles.top())); - p_handles.pop(); - if (!p_handles.empty()) { - /* got back to another dir, read next so it's valid */ - p_dir.remove_name(); - dir_read_next(static_cast(p_handles.top()), curd, tp, p_dir); - p_current = directory_entry{std::move(curd), tp}; - } + + bool empty() const noexcept { + return p_current.path().empty(); } -} + + directory_entry const &front() const noexcept { + return p_current; + } + + ~rdir_range_impl() { + close(); + } + + directory_entry p_current{}; + path p_dir{}; + hstack p_handles{}; +}; } /* namespace detail */ } /* namesapce fs */ @@ -289,6 +323,49 @@ OSTD_EXPORT void rdir_range_impl::read_next() { namespace ostd { namespace fs { +OSTD_EXPORT directory_range::directory_range(path const &p): + p_impl{std::make_shared()} +{ + p_impl->open(p); +} + +OSTD_EXPORT bool directory_range::empty() const noexcept { + return p_impl->empty(); +} + +OSTD_EXPORT void directory_range::pop_front() { + p_impl->read_next(); +} + +OSTD_EXPORT directory_range::reference directory_range::front() const noexcept { + return p_impl->front(); +} + +OSTD_EXPORT recursive_directory_range::recursive_directory_range(path const &p): + p_impl{std::make_shared()} +{ + p_impl->open(p); +} + +OSTD_EXPORT bool recursive_directory_range::empty() const noexcept { + return p_impl->empty(); +} + +OSTD_EXPORT void recursive_directory_range::pop_front() { + p_impl->read_next(); +} + +OSTD_EXPORT recursive_directory_range::reference +recursive_directory_range::front() const noexcept { + return p_impl->front(); +} + +} /* namespace fs */ +} /* namespace ostd */ + +namespace ostd { +namespace fs { + OSTD_EXPORT path current_path() { auto pmax = pathconf(".", _PC_PATH_MAX); std::vector rbuf; diff --git a/src/win32/path.cc b/src/win32/path.cc deleted file mode 100644 index de9dbd8..0000000 --- a/src/win32/path.cc +++ /dev/null @@ -1,6 +0,0 @@ -/* 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"