The Artima Developer Community
Sponsored Link

The C++ Source
Listing 4 - Implementation of readdir_sequence::const_iterator class

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



Google
  Web Artima.com   
Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use