<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2015.  All rights reserved
 */
#include    "../../StroikaPreComp.h"

#if     qPlatform_Windows
#include    <windows.h>
#elif   qPlatform_POSIX
#include    <dirent.h>
#endif

#include    "../../Debug/Trace.h"
#include    "../../Execution/ErrNoException.h"
#if     qPlatform_Windows
#include    "../../Execution/Platform/Windows/Exception.h"
#endif
#include    "../../IO/FileAccessException.h"

#include    "DirectoryIterator.h"





// Comment this in to turn on aggressive noisy DbgTrace in this module
//#define   USE_NOISY_TRACE_IN_THIS_MODULE_       1





using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Characters;
using   namespace   Stroika::Foundation::IO;
using   namespace   Stroika::Foundation::IO::FileSystem;
using   namespace   Stroika::Foundation::Traversal;

#if     qPlatform_Windows
using   Execution::Platform::Windows::ThrowIfFalseGetLastError;
#endif
using   Execution::ThrowIfError_errno_t;



class   DirectoryIterator::Rep_ : public Iterator<String>::IRep {
private:
#if     qPlatform_Windows
    String          fDirName_;
    HANDLE          fHandle_            { INVALID_HANDLE_VALUE };
    WIN32_FIND_DATA fFindFileData_;
    int             fSeekOffset_        { 0 };
#elif   qPlatform_POSIX
    DIR*            fDirIt_             { nullptr };
    dirent          fDirEntBuf_;        // intentionally uninitialized (done by readdir)
    dirent*         fCur_               { nullptr };
#endif

public:
    Rep_ (const String& dir)
#if     qPlatform_Windows
        : fDirName_ (dir)
#elif   qPlatform_POSIX
        : fDirIt_ { ::opendir (dir.AsSDKString ().c_str ()) }
#endif
    {
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
        DbgTrace (L"Entering DirectoryIterator::Rep_::CTOR('%s')", dir.c_str ());
#endif
        try {
#if     qPlatform_Windows
            (void)::memset (&fFindFileData_, 0, sizeof (fFindFileData_));
            fHandle_ = ::FindFirstFile ((dir + L"\\*").AsSDKString ().c_str (), &fFindFileData_);
#elif   qPlatform_POSIX
            if (fDirIt_ == nullptr)
            {
                Execution::ThrowIfError_errno_t ();
            }
            else {
                ThrowIfError_errno_t (::readdir_r (fDirIt_, &fDirEntBuf_, &fCur_));
                Assert (fCur_ == nullptr or fCur_ == &fDirEntBuf_);
            }
#endif
        }
        Stroika_Foundation_IO_FileAccessException_CATCH_REBIND_FILENAMESONLY_HELPER(dir);
    }
#if     qPlatform_Windows
    Rep_ (const String& dir, int seekPos)
        : fDirName_ (dir)
    {
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
        DbgTrace (L"Entering DirectoryIterator::Rep_::CTOR('%s',seekPos=%d)", dir.c_str (), seekPos);
#endif
        (void)::memset (&fFindFileData_, 0, sizeof (fFindFileData_));
        fHandle_ = ::FindFirstFile ((dir + L"\\*").AsSDKString ().c_str (), &fFindFileData_);
        for (int i = 0; i < seekPos; ++i) {
            if (::FindNextFile (fHandle_, &fFindFileData_) == 0) {
                ::FindClose (fHandle_);
                fHandle_ = INVALID_HANDLE_VALUE;
            }
            else {
                fSeekOffset_++;
            }
        }
    }
#elif   qPlatform_POSIX
    Rep_ (DIR* dirObj)
        : fDirIt_ { dirObj } {
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
        DbgTrace (L"Entering DirectoryIterator::Rep_::CTOR(dirObj=%x)", int(dirObj));
#endif
        if (fDirIt_ != nullptr)
        {
            ThrowIfError_errno_t (::readdir_r (fDirIt_, &fDirEntBuf_, &fCur_));
            Assert (fCur_ == nullptr or fCur_ == &fDirEntBuf_);
        }
    }
#endif
    virtual ~Rep_ ()
    {
#if         qPlatform_Windows
        if (fHandle_ != INVALID_HANDLE_VALUE) {
            ::FindClose (fHandle_);
        }
#elif   qPlatform_POSIX
        if (fDirIt_ != nullptr) {
            ::closedir (fDirIt_);
        }
#endif
    }
    virtual void    More (Memory::Optional<String>* result, bool advance) override
    {
        RequireNotNull (result);
        result->clear ();
#if     qPlatform_Windows
        if (advance) {
            Require (fHandle_ != INVALID_HANDLE_VALUE);
            memset (&fFindFileData_, 0, sizeof (fFindFileData_));
            if (::FindNextFile (fHandle_, &fFindFileData_) == 0) {
                ::FindClose (fHandle_);
                fHandle_ = INVALID_HANDLE_VALUE;
            }
        }
        if (fHandle_ != INVALID_HANDLE_VALUE) {
            *result = String::FromSDKString (fFindFileData_.cFileName);
        }
#elif   qPlatform_POSIX
        if (advance) {
            RequireNotNull (fCur_);
            RequireNotNull (fDirIt_);
            ThrowIfError_errno_t (::readdir_r (fDirIt_, &fDirEntBuf_, &fCur_));
            Assert (fCur_ == nullptr or fCur_ == &fDirEntBuf_);
        }
        if (fCur_ != nullptr) {
            *result = String::FromSDKString (fCur_->d_name);
        }
#endif
    }
    virtual bool    Equals (const Iterator<String>::IRep* rhs) const override
    {<commit_msg>allow EBADF and dont throw on iterator - appears legal by docs (unclear) and happens on AIX at EOF. Just add asserts<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2015.  All rights reserved
 */
#include    "../../StroikaPreComp.h"

#if     qPlatform_Windows
#include    <windows.h>
#elif   qPlatform_POSIX
#include    <dirent.h>
#endif

#include    "../../Debug/Trace.h"
#include    "../../Execution/ErrNoException.h"
#if     qPlatform_Windows
#include    "../../Execution/Platform/Windows/Exception.h"
#endif
#include    "../../IO/FileAccessException.h"

#include    "DirectoryIterator.h"





// Comment this in to turn on aggressive noisy DbgTrace in this module
//#define   USE_NOISY_TRACE_IN_THIS_MODULE_       1





using   namespace   Stroika::Foundation;
using   namespace   Stroika::Foundation::Characters;
using   namespace   Stroika::Foundation::IO;
using   namespace   Stroika::Foundation::IO::FileSystem;
using   namespace   Stroika::Foundation::Traversal;

#if     qPlatform_Windows
using   Execution::Platform::Windows::ThrowIfFalseGetLastError;
#endif
using   Execution::ThrowIfError_errno_t;



class   DirectoryIterator::Rep_ : public Iterator<String>::IRep {
private:
#if     qPlatform_Windows
    String          fDirName_;
    HANDLE          fHandle_            { INVALID_HANDLE_VALUE };
    WIN32_FIND_DATA fFindFileData_;
    int             fSeekOffset_        { 0 };
#elif   qPlatform_POSIX
    DIR*            fDirIt_             { nullptr };
    dirent          fDirEntBuf_;        // intentionally uninitialized (done by readdir)
    dirent*         fCur_               { nullptr };
#endif

public:
    Rep_ (const String& dir)
#if     qPlatform_Windows
        : fDirName_ (dir)
#elif   qPlatform_POSIX
        : fDirIt_ { ::opendir (dir.AsSDKString ().c_str ()) }
#endif
    {
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
        DbgTrace (L"Entering DirectoryIterator::Rep_::CTOR('%s')", dir.c_str ());
#endif
        try {
#if     qPlatform_Windows
            (void)::memset (&fFindFileData_, 0, sizeof (fFindFileData_));
            fHandle_ = ::FindFirstFile ((dir + L"\\*").AsSDKString ().c_str (), &fFindFileData_);
#elif   qPlatform_POSIX
            if (fDirIt_ == nullptr)
            {
                Execution::ThrowIfError_errno_t ();
            }
            else {
                ThrowIfError_errno_t (::readdir_r (fDirIt_, &fDirEntBuf_, &fCur_));
                Assert (fCur_ == nullptr or fCur_ == &fDirEntBuf_);
            }
#endif
        }
        Stroika_Foundation_IO_FileAccessException_CATCH_REBIND_FILENAMESONLY_HELPER(dir);
    }
#if     qPlatform_Windows
    Rep_ (const String& dir, int seekPos)
        : fDirName_ (dir)
    {
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
        DbgTrace (L"Entering DirectoryIterator::Rep_::CTOR('%s',seekPos=%d)", dir.c_str (), seekPos);
#endif
        (void)::memset (&fFindFileData_, 0, sizeof (fFindFileData_));
        fHandle_ = ::FindFirstFile ((dir + L"\\*").AsSDKString ().c_str (), &fFindFileData_);
        for (int i = 0; i < seekPos; ++i) {
            if (::FindNextFile (fHandle_, &fFindFileData_) == 0) {
                ::FindClose (fHandle_);
                fHandle_ = INVALID_HANDLE_VALUE;
            }
            else {
                fSeekOffset_++;
            }
        }
    }
#elif   qPlatform_POSIX
    Rep_ (DIR* dirObj)
        : fDirIt_ { dirObj } {
#if     USE_NOISY_TRACE_IN_THIS_MODULE_
        DbgTrace (L"Entering DirectoryIterator::Rep_::CTOR(dirObj=%x)", int(dirObj));
#endif
        if (fDirIt_ != nullptr)
        {
            ThrowIfError_errno_t (::readdir_r (fDirIt_, &fDirEntBuf_, &fCur_));
            Assert (fCur_ == nullptr or fCur_ == &fDirEntBuf_);
        }
    }
#endif
    virtual ~Rep_ ()
    {
#if         qPlatform_Windows
        if (fHandle_ != INVALID_HANDLE_VALUE) {
            ::FindClose (fHandle_);
        }
#elif   qPlatform_POSIX
        if (fDirIt_ != nullptr) {
            ::closedir (fDirIt_);
        }
#endif
    }
    virtual void    More (Memory::Optional<String>* result, bool advance) override
    {
        RequireNotNull (result);
        result->clear ();
#if     qPlatform_Windows
        if (advance) {
            Require (fHandle_ != INVALID_HANDLE_VALUE);
            memset (&fFindFileData_, 0, sizeof (fFindFileData_));
            if (::FindNextFile (fHandle_, &fFindFileData_) == 0) {
                ::FindClose (fHandle_);
                fHandle_ = INVALID_HANDLE_VALUE;
            }
        }
        if (fHandle_ != INVALID_HANDLE_VALUE) {
            *result = String::FromSDKString (fFindFileData_.cFileName);
        }
#elif   qPlatform_POSIX
        if (advance) {
            RequireNotNull (fCur_);
            RequireNotNull (fDirIt_);
            errno_t e = ::readdir_r (fDirIt_, &fDirEntBuf_, &fCur_);
            if (e == EBADF) {
                Assert (fCur_ == nullptr );
            }
            else {
                ThrowIfError_errno_t (e);
            }
            Assert (fCur_ == nullptr or fCur_ == &fDirEntBuf_);
        }
        if (fCur_ != nullptr) {
            *result = String::FromSDKString (fCur_->d_name);
        }
#endif
    }
    virtual bool    Equals (const Iterator<String>::IRep* rhs) const override
    {
{'fraction_non_alphanumeric': 0.11679188213484243, 'fraction_numerical': 0.0035125378085666893, 'mean_word_length': 2.249841471147749, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2770544', 'n_tokens_mistral': 3362, 'n_tokens_neox': 3220, 'n_words': 680}