|
|
|
Sponsored Link •
|
Defines a const_iterator for readdir_sequence
/* /////////////////////////////////////////////////////////////
* Extract from unixstl_readdir_sequence.h
*
* www: http://www.synesis.com.au/unixstl
* http://www.unixstl.org/
*
* Copyright (C) 2002-2004, Synesis Software Pty Ltd.
* (Licensed under the Synesis Software Standard Source License:
* http://www.synesis.com.au/licenses/ssssl.html)
* ////////////////////////////////////////////////////////// */
... // Includes (as shown in Listing 3)
class readdir_sequence::const_iterator
: public stlsoft::iterator_base < std::input_iterator_tag
, readdir_sequence::value_type
, ptrdiff_t
, readdir_sequence::value_type*
, readdir_sequence::value_type&
>
{
private:
typedef readdir_sequence::string_type string_type;
public:
typedef const_iterator class_type;
typedef readdir_sequence::value_type value_type;
// Construction
private:
friend class readdir_sequence;
const_iterator(DIR *dir, string_type const &directory, unsigned flags);
public:
const_iterator();
const_iterator(class_type const &rhs);
~const_iterator();
class_type const &operator =(class_type const &rhs);
// Accessors
public:
value_type operator *() const;
class_type &operator ++();
class_type operator ++(int);
bool operator ==(class_type const &rhs) const;
bool operator !=(class_type const &rhs) const;
// Members
private:
struct rds_shared_handle;
rds_shared_handle *m_handle; // The DIR handle, shared with other iterator instances
struct dirent *m_entry; // The current entry
unsigned m_flags; // flags. (Only non-const, to allow copy assignment)
string_type m_scratch; // Holds the directory, and is a scratch area
size_type m_dirLen; // The length of the directory
};
struct readdir_sequence::const_iterator::rds_shared_handle
{
public:
typedef rds_shared_handle class_type;
// Members
public:
DIR *dir;
private:
int cRefs;
public:
explicit rds_shared_handle(DIR *d);
void AddRef();
void Release();
#if defined(__GNUC__) /* Silly old "helpful" GCC! */
protected:
#else /* ? __GNUC__ */
private:
#endif /* __GNUC__ */
~rds_shared_handle();
private:
rds_shared_handle(class_type const &);
class_type &operator =(class_type const &);
};
/* /////////////////////////////////////////////////////////////////////////////
* Implementation
*/
inline readdir_sequence::const_iterator::const_iterator(DIR *dir
, readdir_sequence::string_type const &directory
, unsigned flags)
: m_handle(new rds_shared_handle(dir))
, m_entry(NULL)
, m_flags(flags)
, m_scratch(directory)
, m_dirLen(directory.length())
{
unixstl_assert(0 != traits_type::has_dir_end(stlsoft_ns_qual(c_str_ptr)(m_scratch)));
if(NULL != m_handle)
{
operator ++();
}
}
inline readdir_sequence::const_iterator::const_iterator()
: m_handle(NULL)
, m_entry(NULL)
, m_dirLen(0)
{}
inline readdir_sequence::const_iterator::const_iterator(class_type const &rhs)
: m_handle(rhs.m_handle)
, m_entry(rhs.m_entry)
, m_scratch(rhs.m_scratch)
, m_dirLen(rhs.m_dirLen)
{
if(NULL != m_handle)
{
m_handle->AddRef();
}
}
inline readdir_sequence::const_iterator::~const_iterator()
{
if(NULL != m_handle)
{
m_handle->Release();
}
}
inline readdir_sequence::const_iterator const &readdir_sequence::const_iterator::operator =(readdir_sequence::const_iterator const &rhs)
{
if(NULL != m_handle)
{
m_handle->Release();
}
m_handle = rhs.m_handle;
m_entry = rhs.m_entry;
m_flags = rhs.m_flags;
m_scratch = rhs.m_scratch;
m_dirLen = rhs.m_dirLen;
if(NULL != m_handle)
{
m_handle->AddRef();
}
return *this;
}
inline readdir_sequence::const_iterator::value_type readdir_sequence::const_iterator::operator *() const
{
unixstl_message_assert( "Dereferencing invalid iterator", NULL != m_entry);
return m_entry;
}
inline readdir_sequence::const_iterator &readdir_sequence::const_iterator::operator ++()
{
unixstl_message_assert( "Incrementing invalid iterator", NULL != m_handle);
for(;;)
{
m_entry = readdir(m_handle->dir);
if(NULL != m_entry)
{
unixstl_assert(NULL != m_entry->d_name);
if(0 == (m_flags & includeDots))
{
if(traits_type::is_dots(m_entry->d_name))
{
continue; // Don't want dots; skip it
}
}
if((m_flags & (directories | files)) != (directories | files))
{
// Now need to process the file, by using stat
struct stat st;
// Truncate the scratch to the directory path, ...
m_scratch.resize(m_dirLen);
// ... and add the file
m_scratch += m_entry->d_name;
if(0 != stat(stlsoft_ns_qual(c_str_ptr)(m_scratch), &st))
{
// Failed to get info from entry. Must assume it is
// dead, so skip it
continue;
}
else
{
if(m_flags & directories) // Want directories
{
if(S_IFDIR == (st.st_mode & S_IFDIR))
{
// It is a directory, so accept it
break;
}
}
if(m_flags & files) // Want files
{
if(S_IFREG == (st.st_mode & S_IFREG))
{
// It is a file, so accept it
break;
}
}
continue; // Not a match, so skip this entry
}
}
}
break; // No entries left, so break out
}
if(NULL == m_entry)
{
unixstl_assert(NULL != m_handle);
m_handle->Release();
m_handle = NULL;
}
return *this;
}
inline readdir_sequence::const_iterator readdir_sequence::const_iterator::operator ++(int)
{
class_type ret(*this);
operator ++();
return ret;
}
inline bool readdir_sequence::const_iterator::operator ==(readdir_sequence::const_iterator const &rhs) const
{
unixstl_assert(NULL == m_handle || NULL == rhs.m_handle || m_handle->dir == rhs.m_handle->dir);
return m_entry == rhs.m_entry;
}
inline bool readdir_sequence::const_iterator::operator !=(readdir_sequence::const_iterator const &rhs) const
{
return !operator ==(rhs);
}
inline /* explicit */ readdir_sequence::const_iterator::rds_shared_handle::rds_shared_handle(DIR *d)
: dir(d)
, cRefs(1)
{}
inline void readdir_sequence::const_iterator::rds_shared_handle::AddRef()
{
++cRefs;
}
inline void readdir_sequence::const_iterator::rds_shared_handle::Release()
{
if(0 == --cRefs)
{
delete this;
}
}
inline readdir_sequence::const_iterator::rds_shared_handle::~rds_shared_handle()
{
unixstl_message_assert( "Shared handle destroyed with outstanding references!"
, 0 == cRefs);
if(NULL != dir)
{
closedir(dir);
}
}
|
Sponsored Links
|