diff --git a/CMakeLists.txt b/CMakeLists.txt index 8eda08d..87b283d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,4 +4,4 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU" # Enable C++11 mode on GCC / Clang set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") endif() -add_executable(path_demo path_demo.cpp filesystem/path.h filesystem/resolver.h) +add_executable(path_demo path_demo.cpp filesystem/path.h filesystem/resolver.h filesystem/directory.h) diff --git a/filesystem/directory.h b/filesystem/directory.h new file mode 100644 index 0000000..61f037c --- /dev/null +++ b/filesystem/directory.h @@ -0,0 +1,152 @@ + +/* + * reference https://docs.microsoft.com/zh-cn/cpp/c-runtime-library/reference/findfirst-functions?f1url=https%3A%2F%2Fmsdn.microsoft.com%2Fquery%2Fdev15.query%3FappId%3DDev15IDEF1%26l%3DZH-CN%26k%3Dk(CORECRT_IO%2F_findfirst);k(_findfirst);k(DevLang-C%2B%2B);k(TargetOS-Windows)%26rd%3Dtrue&view=vs-2019 + * reference http://www.man7.org/linux/man-pages/man3/opendir.3.html + * + * Copyright (c) 2019 tangm421 + * + * All rights reserved. Use of this source code is governed by a + * BSD-style license that can be found in the LICENSE file. + */ + +#pragma once + +#include "path.h" + +#if defined(_WIN32) +#include +#else +#include +#include +#endif + +NAMESPACE_BEGIN(filesystem) + +class directory : public path +{ +public: + directory(const path& dir) : path(dir), m_dir(dir) {} + + class iterator + { + public: + iterator() /* default ctor indicates the end iterator */ +#if defined(_WIN32) + : m_handle(-1) {} +#else + : m_handle(NULL), m_data(NULL) {} +#endif + + iterator(const directory& dir) { + m_dir = dir; +#if defined(_WIN32) + std::string search_path(dir.make_absolute().str() + "/*.*"); + m_handle = _findfirst(search_path.c_str(), &m_data); + if (is_valid_handler()) + { + m_result = m_dir / m_data.name; + } + else /* an error occurs or reaching the end */ + { + /* do nothing */ + } +#else + m_handle = opendir(dir.make_absolute().str().c_str()); + ++*this; /* here we do find the first directory entry like the begin iterator does */ +#endif + } + ~iterator() { + if (is_valid_handler()) + { +#if defined(_WIN32) + _findclose(m_handle); + m_handle = -1; +#else + closedir(m_handle); + m_handle = NULL; + m_data = NULL; +#endif + } + } + + iterator& operator++() { + if (is_valid_handler()) + { +#if defined(_WIN32) + if (_findnext(m_handle, &m_data)) + { + if (ENOENT == errno) /* reaching the end */ + { + m_result = path(); + } + else /* an error occurs */ + { + /* do nothing because the next call of this function will not do anything */ + } + } + else + { + m_result = m_dir / m_data.name; + } +#else + errno = 0; + m_data = readdir(m_handle); + if (0 != errno) /* an error occurs */ + { + /* do nothing because the next call of this function will not do anything */ + } + if (!m_data) /* reaching the end */ + { + m_result = path(); + } + else + { + m_result = m_dir / m_data->d_name; + } +#endif + } + return *this; + } + bool operator!=(const iterator& rhs) const { + return !(*this == rhs); + } + bool operator==(const iterator& rhs) const { + return **this == *rhs; + } + const path& operator*() const { + return m_result; + } + const path* operator->() const { + return &m_result; + } + + protected: + bool is_valid_handler() const { +#if defined(_WIN32) + return -1 != m_handle; +#else + return NULL != m_handle; +#endif + } + + private: + path m_dir; + path m_result; +#if defined(_WIN32) + intptr_t m_handle; + _finddata_t m_data; +#else + DIR* m_handle; + struct dirent* m_data; +#endif + }; + + iterator begin() const { return iterator(*this); } + iterator end() const { static iterator static_end; return static_end; }; + +private: + path m_dir; +}; + + +NAMESPACE_END(filesystem) diff --git a/path_demo.cpp b/path_demo.cpp index 266c661..0c3eaf0 100644 --- a/path_demo.cpp +++ b/path_demo.cpp @@ -1,6 +1,7 @@ #include #include "filesystem/path.h" #include "filesystem/resolver.h" +#include "filesystem/directory.h" using namespace std; using namespace filesystem; @@ -44,5 +45,35 @@ int main(int argc, char **argv) { cout << "resolve(filesystem/path.h) = " << resolver().resolve("filesystem/path.h") << endl; cout << "resolve(nonexistant) = " << resolver().resolve("nonexistant") << endl; + + ////////////////////////////////////////////////////////////////////////// + directory dir1("."); + directory dir2(".."); + if (dir1 == dir2) + { + cout << "dir1:" << dir1 << " equal to dir2:" << dir2 << endl; + } + else + { + cout << "dir1:" << dir1 << " not equal to dir2:" << dir2 << endl; + } + + directory::iterator begin(dir1); + directory::iterator end; + for (; begin != end; ++begin) + { + cout << *begin << endl; + } + + directory::iterator b = dir2.begin(); + directory::iterator e = dir2.end(); + for (; b != e; ++b) + { + if (b->is_file()) + { + cout << *b << endl; + } + } + return 0; }