4#include "Stroika/Foundation/StroikaPreComp.h"
6#if qStroika_Foundation_Common_Platform_Windows
8#elif qStroika_Foundation_Common_Platform_POSIX
17#include "Stroika/Foundation/Execution/Exceptions.h"
18#if qStroika_Foundation_Common_Platform_Windows
19#include "Stroika/Foundation/Execution/Platform/Windows/Exception.h"
31using namespace Stroika::Foundation::IO;
33using namespace Stroika::Foundation::Traversal;
35using Execution::ThrowPOSIXErrNo;
40class DirectoryIterator::Rep_ :
public Iterator<filesystem::path>::IRep {
42 IteratorReturnType fIteratorReturnType_;
44 filesystem::path fReportPrefix_;
45#if qStroika_Foundation_Common_Platform_POSIX
46 DIR* fDirIt_{
nullptr};
47 dirent* fCur_{
nullptr};
48#elif qStroika_Foundation_Common_Platform_Windows
49 HANDLE fHandle_{INVALID_HANDLE_VALUE};
50 WIN32_FIND_DATA fFindFileData_{};
55 Rep_ (
const String& dir, IteratorReturnType iteratorReturns)
56 : fIteratorReturnType_{iteratorReturns}
58 , fReportPrefix_{mkReportPrefix_ (dir.As<filesystem::path> (), iteratorReturns)}
59#if qStroika_Foundation_Common_Platform_POSIX
60 , fDirIt_{::opendir (dir.AsSDKString ().c_str ())}
63#if USE_NOISY_TRACE_IN_THIS_MODULE_
66#if qStroika_Foundation_Common_Platform_POSIX
67 if (fDirIt_ ==
nullptr) {
72 if ((fCur_ = ::readdir (fDirIt_)) ==
nullptr) {
77 if (fCur_ !=
nullptr and fCur_->d_name[0] ==
'.' and
78 (CString::Equals (fCur_->d_name, SDKSTR (
".")) or CString::Equals (fCur_->d_name, SDKSTR (
"..")))) {
81#elif qStroika_Foundation_Common_Platform_Windows
82 fHandle_ = ::FindFirstFile ((dir + L
"\\*").AsSDKString ().c_str (), &fFindFileData_);
83 while (fHandle_ != INVALID_HANDLE_VALUE and
84 (CString::Equals (fFindFileData_.cFileName, SDKSTR (
".")) or CString::Equals (fFindFileData_.cFileName, SDKSTR (
"..")))) {
89#if qStroika_Foundation_Common_Platform_POSIX
90 Rep_ (
const String& dirName,
const optional<ino_t>& curInode, IteratorReturnType iteratorReturns)
91 : fIteratorReturnType_{iteratorReturns}
93 , fReportPrefix_{mkReportPrefix_ (dirName.As<filesystem::path> (), iteratorReturns)}
94 , fDirIt_{::opendir (dirName.AsSDKString ().c_str ())}
96 if (fDirIt_ ==
nullptr) {
99#if USE_NOISY_TRACE_IN_THIS_MODULE_
104 fCur_ = ::readdir (fDirIt_);
105 }
while (fCur_ !=
nullptr and fCur_->d_ino != *curInode);
108#elif qStroika_Foundation_Common_Platform_Windows
110 Rep_ (
const String& dir,
const optional<String>& name, IteratorReturnType iteratorReturns)
111 : fIteratorReturnType_{iteratorReturns}
113 , fReportPrefix_{mkReportPrefix_ (dir.As<filesystem::path> (), iteratorReturns)}
115#if USE_NOISY_TRACE_IN_THIS_MODULE_
119 fHandle_ = ::FindFirstFile ((dir + L
"\\*").AsSDKString ().c_str (), &fFindFileData_);
120 while (fHandle_ != INVALID_HANDLE_VALUE and
String::FromSDKString (fFindFileData_.cFileName) != name) {
128#if qStroika_Foundation_Common_Platform_POSIX
129 if (fDirIt_ !=
nullptr) {
130 ::closedir (fDirIt_);
132#elif qStroika_Foundation_Common_Platform_Windows
133 if (fHandle_ != INVALID_HANDLE_VALUE) {
134 ::FindClose (fHandle_);
138 virtual bool AtEnd ()
const override
140#if qStroika_Foundation_Common_Platform_POSIX
141 return fCur_ ==
nullptr;
142#elif qStroika_Foundation_Common_Platform_Windows
143 return fHandle_ == INVALID_HANDLE_VALUE;
148 virtual optional<filesystem::path>
Current ()
const override
150#if qStroika_Foundation_Common_Platform_POSIX
151 if (fCur_ ==
nullptr) {
154 return fReportPrefix_ / fCur_->d_name;
155#elif qStroika_Foundation_Common_Platform_Windows
156 if (fHandle_ == INVALID_HANDLE_VALUE) {
159 return fReportPrefix_ / fFindFileData_.cFileName;
164 virtual optional<filesystem::path> More ()
override
167#if qStroika_Foundation_Common_Platform_POSIX
172 fCur_ = ::readdir (fDirIt_);
173 if (fCur_ ==
nullptr) {
175 if (errno != EBADF and errno != 0) {
179 if (fCur_ !=
nullptr and fCur_->d_name[0] ==
'.' and
180 (CString::Equals (fCur_->d_name, SDKSTR (
".")) or CString::Equals (fCur_->d_name, SDKSTR (
"..")))) {
183 if (fCur_ !=
nullptr) {
184 return fReportPrefix_ / fCur_->d_name;
186#elif qStroika_Foundation_Common_Platform_Windows
188 Require (fHandle_ != INVALID_HANDLE_VALUE);
189 (void)::memset (&fFindFileData_, 0,
sizeof (fFindFileData_));
190 if (::FindNextFile (fHandle_, &fFindFileData_) == 0) {
191 ::FindClose (fHandle_);
192 fHandle_ = INVALID_HANDLE_VALUE;
194 if (fHandle_ != INVALID_HANDLE_VALUE and
195 (CString::Equals (fFindFileData_.cFileName, SDKSTR (
".")) or CString::Equals (fFindFileData_.cFileName, SDKSTR (
"..")))) {
198 if (fHandle_ != INVALID_HANDLE_VALUE) {
199 return fReportPrefix_ / fFindFileData_.cFileName;
209 const Rep_& rrhs = *Debug::UncheckedDynamicCast<const Rep_*> (rhs);
210#if qStroika_Foundation_Common_Platform_POSIX
211 return fDirName_ == rrhs.fDirName_ and fIteratorReturnType_ == rrhs.fIteratorReturnType_ and
212 ((fCur_ == rrhs.fCur_ and fCur_ ==
nullptr) or (rrhs.fCur_ !=
nullptr and fCur_->d_ino == rrhs.fCur_->d_ino));
213#elif qStroika_Foundation_Common_Platform_Windows
214 return fHandle_ == rrhs.fHandle_;
217 virtual unique_ptr<IRep> Clone ()
const override
219#if USE_NOISY_TRACE_IN_THIS_MODULE_
223#if qStroika_Foundation_Common_Platform_POSIX
254 return make_unique<Rep_> (fDirName_, fCur_ ==
nullptr ? optional<ino_t>{} : fCur_->d_ino, fIteratorReturnType_);
255#elif qStroika_Foundation_Common_Platform_Windows
256 return make_unique<Rep_> (fDirName_, fHandle_ == INVALID_HANDLE_VALUE ? optional<String>{} :
String::FromSDKString (fFindFileData_.cFileName),
257 fIteratorReturnType_);
262 static filesystem::path mkReportPrefix_ (
const filesystem::path& dirName, IteratorReturnType iteratorReturns)
264 switch (iteratorReturns) {
265 case IteratorReturnType::eFilenameOnly:
266 return filesystem::path{};
267 case IteratorReturnType::eDirPlusFilename:
269 case IteratorReturnType::eFullPathName:
270 return filesystem::absolute (dirName);
273 return filesystem::path{};
283DirectoryIterator::DirectoryIterator (
const filesystem::path& directoryName, IteratorReturnType iteratorReturns)
284 :
Iterator<filesystem::path>{make_unique<Rep_> (
String{directoryName}, iteratorReturns)}
#define AssertNotImplemented()
#define RequireMember(p, c)
#define RequireNotNull(p)
#define AssertNotReached()
bool Equals(const T *lhs, const T *rhs)
strcmp or wsccmp() as appropriate == 0
#define qStroika_ATTRIBUTE_NO_UNIQUE_ADDRESS_VCFORCE
[[msvc::no_unique_address]] isn't always broken in MSVC. Annotate with this on things where its not b...
String is like std::u32string, except it is much easier to use, often much more space efficient,...
static String FromSDKString(const SDKChar *from)
NOT a real mutex - just a debugging infrastructure support tool so in debug builds can be assured thr...
unique_lock< AssertExternallySynchronizedChecker > WriteContext
Instantiate AssertExternallySynchronizedChecker::WriteContext to designate an area of code where prot...
shared_lock< const AssertExternallySynchronizedChecker > ReadContext
Instantiate AssertExternallySynchronizedChecker::ReadContext to designate an area of code where prote...
static void ThrowPOSIXErrNo(errno_t errNo, const path &p1={}, const path &p2={})
treats errNo as a POSIX errno value, and throws a FileSystem::Exception (subclass of @std::filesystem...
Implementation detail for iterator implementors.
An Iterator<T> is a copyable object which allows traversing the contents of some container.
nonvirtual const T & Current() const
Returns the value of the current item visited by the Iterator<T>, and is illegal to call if AtEnd()
nonvirtual bool AtEnd() const
AtEnd () means there is nothing left in this iterator (a synonym for (it == container....
void ThrowPOSIXErrNo(errno_t errNo=errno)
treats errNo as a POSIX errno value, and throws a SystemError (subclass of @std::system_error) except...