add recursive directory range
parent
4ef512effa
commit
ad635c8a23
68
ostd/path.hh
68
ostd/path.hh
|
@ -23,6 +23,8 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <stack>
|
||||||
|
#include <list>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
@ -721,6 +723,9 @@ private:
|
||||||
ostd::path p_path{};
|
ostd::path p_path{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
}
|
||||||
|
|
||||||
struct directory_range: input_range<directory_range> {
|
struct directory_range: input_range<directory_range> {
|
||||||
using range_category = input_range_tag;
|
using range_category = input_range_tag;
|
||||||
using value_type = directory_entry;
|
using value_type = directory_entry;
|
||||||
|
@ -732,7 +737,7 @@ struct directory_range: input_range<directory_range> {
|
||||||
open(p);
|
open(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
directory_range(directory_range const &r) noexcept:
|
directory_range(directory_range const &r):
|
||||||
p_current(r.p_current), p_dir(r.p_dir),
|
p_current(r.p_current), p_dir(r.p_dir),
|
||||||
p_handle(r.p_handle), p_owned(false)
|
p_handle(r.p_handle), p_owned(false)
|
||||||
{}
|
{}
|
||||||
|
@ -761,9 +766,9 @@ struct directory_range: input_range<directory_range> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void open(path const &p);
|
OSTD_EXPORT void open(path const &p);
|
||||||
void close() noexcept;
|
OSTD_EXPORT void close() noexcept;
|
||||||
void read_next();
|
OSTD_EXPORT void read_next();
|
||||||
|
|
||||||
directory_entry p_current{};
|
directory_entry p_current{};
|
||||||
path p_dir{};
|
path p_dir{};
|
||||||
|
@ -771,6 +776,61 @@ private:
|
||||||
bool p_owned = false;
|
bool p_owned = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct recursive_directory_range: input_range<recursive_directory_range> {
|
||||||
|
using range_category = input_range_tag;
|
||||||
|
using value_type = directory_entry;
|
||||||
|
using reference = directory_entry const &;
|
||||||
|
using size_type = std::size_t;
|
||||||
|
|
||||||
|
recursive_directory_range() = delete;
|
||||||
|
recursive_directory_range(path const &p) {
|
||||||
|
open(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
recursive_directory_range(recursive_directory_range const &r):
|
||||||
|
p_current(r.p_current), p_dir(r.p_dir),
|
||||||
|
p_stack(r.p_stack), p_owned(false)
|
||||||
|
{}
|
||||||
|
|
||||||
|
~recursive_directory_range() {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
recursive_directory_range &operator=(
|
||||||
|
recursive_directory_range const &r
|
||||||
|
) noexcept {
|
||||||
|
close();
|
||||||
|
p_stack = r.p_stack;
|
||||||
|
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:
|
||||||
|
using hstack = std::stack<void *, std::list<void *>>;
|
||||||
|
|
||||||
|
OSTD_EXPORT void open(path const &p);
|
||||||
|
OSTD_EXPORT void close() noexcept;
|
||||||
|
OSTD_EXPORT void read_next();
|
||||||
|
|
||||||
|
directory_entry p_current{};
|
||||||
|
path p_dir{};
|
||||||
|
hstack p_handles{};
|
||||||
|
hstack *p_stack = nullptr;
|
||||||
|
bool p_owned = false;
|
||||||
|
};
|
||||||
|
|
||||||
OSTD_EXPORT path cwd();
|
OSTD_EXPORT path cwd();
|
||||||
OSTD_EXPORT path home();
|
OSTD_EXPORT path home();
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,39 @@
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include "ostd/path.hh"
|
#include "ostd/path.hh"
|
||||||
|
|
||||||
namespace ostd {
|
namespace ostd {
|
||||||
namespace fs {
|
namespace fs {
|
||||||
|
|
||||||
void directory_range::open(path const &p) {
|
static void dir_read_next(DIR *dh, directory_entry &cur, path const &base) {
|
||||||
|
struct dirent d;
|
||||||
|
struct dirent *o;
|
||||||
|
for (;;) {
|
||||||
|
if (readdir_r(dh, &d, &o)) {
|
||||||
|
/* FIXME: throw */
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
if (!o) {
|
||||||
|
cur.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
string_range nm{static_cast<char const *>(o->d_name)};
|
||||||
|
if ((nm == ".") || (nm == "..")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
path p{base};
|
||||||
|
p.append(nm);
|
||||||
|
cur.assign(std::move(p));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* dir range */
|
||||||
|
|
||||||
|
OSTD_EXPORT void directory_range::open(path const &p) {
|
||||||
DIR *d = opendir(p.string().data());
|
DIR *d = opendir(p.string().data());
|
||||||
if (!d) {
|
if (!d) {
|
||||||
/* FIXME: throw */
|
/* FIXME: throw */
|
||||||
|
@ -23,7 +49,7 @@ void directory_range::open(path const &p) {
|
||||||
read_next();
|
read_next();
|
||||||
}
|
}
|
||||||
|
|
||||||
void directory_range::close() noexcept {
|
OSTD_EXPORT void directory_range::close() noexcept {
|
||||||
if (!p_owned) {
|
if (!p_owned) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -31,27 +57,78 @@ void directory_range::close() noexcept {
|
||||||
p_owned = false;
|
p_owned = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void directory_range::read_next() {
|
OSTD_EXPORT void directory_range::read_next() {
|
||||||
struct dirent d;
|
dir_read_next(static_cast<DIR *>(p_handle), p_current, p_dir);
|
||||||
struct dirent *o;
|
}
|
||||||
DIR *dh = static_cast<DIR *>(p_handle);
|
|
||||||
for (;;) {
|
/* recursive dir range */
|
||||||
if (readdir_r(dh, &d, &o)) {
|
|
||||||
|
OSTD_EXPORT void recursive_directory_range::open(path const &p) {
|
||||||
|
DIR *d = opendir(p.string().data());
|
||||||
|
if (!d) {
|
||||||
|
/* FIXME: throw */
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
p_dir = p;
|
||||||
|
p_stack = &p_handles;
|
||||||
|
p_stack->push(d);
|
||||||
|
p_owned = true;
|
||||||
|
read_next();
|
||||||
|
}
|
||||||
|
|
||||||
|
OSTD_EXPORT void recursive_directory_range::close() noexcept {
|
||||||
|
if (!p_owned) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (!p_handles.empty()) {
|
||||||
|
closedir(static_cast<DIR *>(p_handles.top()));
|
||||||
|
p_handles.pop();
|
||||||
|
}
|
||||||
|
p_owned = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSTD_EXPORT void recursive_directory_range::read_next() {
|
||||||
|
directory_entry curd;
|
||||||
|
if (p_stack->empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dir_read_next(static_cast<DIR *>(p_stack->top()), curd, p_dir);
|
||||||
|
struct stat sb;
|
||||||
|
/* check if dir and recurse maybe */
|
||||||
|
while (!curd.path().empty()) {
|
||||||
|
if (stat(curd.path().string().data(), &sb) < 0) {
|
||||||
/* FIXME: throw */
|
/* FIXME: throw */
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
if (!o) {
|
if (S_ISDIR(sb.st_mode)) {
|
||||||
p_current.clear();
|
/* directory, recurse into it */
|
||||||
|
DIR *nd = opendir(curd.path().string().data());
|
||||||
|
if (!nd) {
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
p_dir = curd;
|
||||||
|
p_stack->push(nd);
|
||||||
|
dir_read_next(nd, curd, p_dir);
|
||||||
|
p_current = curd;
|
||||||
|
if (curd.path().empty()) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* not a dir, stick with it */
|
||||||
|
p_current = curd;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
string_range nm{static_cast<char const *>(o->d_name)};
|
}
|
||||||
if ((nm == ".") || (nm == "..")) {
|
/* empty result - done with a dir, pop */
|
||||||
continue;
|
closedir(static_cast<DIR *>(p_stack->top()));
|
||||||
}
|
p_stack->pop();
|
||||||
path p{p_dir};
|
if (!p_stack->empty()) {
|
||||||
p.append(nm);
|
p_current.assign(p_dir);
|
||||||
p_current.assign(std::move(p));
|
p_dir.remove_name();
|
||||||
break;
|
} else {
|
||||||
|
p_current.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue