00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00047 #ifndef UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_READDIR_SEQUENCE
00048 #define UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_READDIR_SEQUENCE
00049 
00050 #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
00051 # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_READDIR_SEQUENCE_MAJOR      5
00052 # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_READDIR_SEQUENCE_MINOR      1
00053 # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_READDIR_SEQUENCE_REVISION   7
00054 # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_READDIR_SEQUENCE_EDIT       126
00055 #endif 
00056 
00057 
00058 
00059 
00060 
00061 #ifndef UNIXSTL_INCL_UNIXSTL_H_UNIXSTL
00062 # include <unixstl/unixstl.h>
00063 #endif 
00064 #ifndef UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS
00065 # include <unixstl/filesystem/filesystem_traits.hpp>
00066 #endif 
00067 #ifndef UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_FILE_PATH_BUFFER
00068 # include <unixstl/filesystem/file_path_buffer.hpp>
00069 #endif 
00070 #ifndef UNIXSTL_INCL_UNIXSTL_HPP_ERROR_UNIX_EXCEPTIONS
00071 # include <unixstl/error/exceptions.hpp>
00072 #endif 
00073 
00074 #if defined(PATH_MAX)
00075 # ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_STATIC_STRING
00076 #  include <stlsoft/string/static_string.hpp>
00077 # endif 
00078 #else 
00079 # ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_SIMPLE_STRING
00080 #  include <stlsoft/string/simple_string.hpp>
00081 # endif 
00082 #endif 
00083 #ifndef STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER
00084 # include <stlsoft/util/std/iterator_helper.hpp>
00085 #endif 
00086 #ifndef STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS
00087 # include <stlsoft/collections/util/collections.hpp>
00088 #endif 
00089 
00090 #ifndef STLSOFT_INCL_H_UNISTD
00091 # define STLSOFT_INCL_H_UNISTD
00092 # include <unistd.h>
00093 #endif 
00094 #ifndef STLSOFT_INCL_SYS_H_TYPES
00095 # define STLSOFT_INCL_SYS_H_TYPES
00096 # include <sys/types.h>
00097 #endif 
00098 #ifndef STLSOFT_INCL_SYS_H_STAT
00099 # define STLSOFT_INCL_SYS_H_STAT
00100 # include <sys/stat.h>
00101 #endif 
00102 #ifndef STLSOFT_INCL_H_DIRENT
00103 # define STLSOFT_INCL_H_DIRENT
00104 # include <dirent.h>
00105 #endif 
00106 
00107 
00108 
00109 
00110 
00111 
00112 #ifdef _STLSOFT_NO_NAMESPACES
00113 # define _UNIXSTL_NO_NAMESPACES
00114 #endif 
00115 
00116 
00117 #ifdef _UNIXSTL_NO_NAMESPACES
00118 # define _UNIXSTL_NO_NAMESPACE
00119 #endif 
00120 
00121 #ifndef _UNIXSTL_NO_NAMESPACE
00122 # if defined(_STLSOFT_NO_NAMESPACE) || \
00123      defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
00124 
00125 namespace unixstl
00126 {
00127 # else
00128 
00129 
00130 namespace stlsoft
00131 {
00132 
00133 namespace unixstl_project
00134 {
00135 
00136 # endif 
00137 #endif 
00138 
00139 
00140 
00141 
00142 
00147 class readdir_sequence_exception
00148     : public unix_exception
00149 {
00152 public:
00153     typedef unix_exception              parent_class_type;
00154     typedef readdir_sequence_exception  class_type;
00156 
00159 public:
00160     readdir_sequence_exception(us_char_a_t const* message, us_int_t erno)
00161         : parent_class_type(message, erno)
00162     {}
00164 };
00165 
00166 
00174 class readdir_sequence
00175     : public stlsoft_ns_qual(stl_collection_tag)
00176 {
00179 public:
00181     typedef readdir_sequence                                    class_type;
00182 private:
00183     
00184     typedef us_char_a_t                                         char_type;
00185     typedef filesystem_traits<char_type>                        traits_type;
00186 public:
00188     typedef us_size_t                                           size_type;
00190     class                                                       const_iterator;
00192 #if defined(UNIXSTL_READDIR_SEQUENCE_OLD_VALUE_TYPE)
00193     typedef struct dirent const*                                value_type;
00194 #else 
00195     typedef char_type const*                                    value_type;
00196 #endif 
00198     typedef us_int_t                                            flags_type;
00199 
00200 public:
00201 #if defined(PATH_MAX)
00202     typedef stlsoft_ns_qual(basic_static_string)<   char_type
00203                                                 ,   PATH_MAX
00204                                                 >               string_type;
00205 #else 
00206     typedef stlsoft_ns_qual(basic_simple_string)<   char_type
00207                                                 >               string_type;
00208 #endif 
00210 
00213 public:
00214     enum
00215     {
00216             includeDots     =   0x0008  
00217         ,   directories     =   0x0010  
00218         ,   files           =   0x0020  
00219         ,   fullPath        =   0x0100  
00220         ,   absolutePath    =   0x0200  
00221     };
00223 
00226 public:
00238     template <ss_typename_param_k S>
00239     readdir_sequence(S const& directory, flags_type flags = directories | files)
00240         : m_flags(validate_flags_(flags))
00241         , m_directory(prepare_directory_(stlsoft_ns_qual(c_str_ptr)(directory), flags))
00242     {}
00244 
00247 public:
00251     const_iterator  begin() const;
00255     const_iterator  end() const;
00257 
00260 public:
00262     us_bool_t empty() const;
00263 
00269     string_type const   &get_directory() const;
00270 
00277     flags_type          get_flags() const;
00279 
00282 private:
00284     static flags_type   validate_flags_(flags_type flags);
00285 
00287     static string_type  prepare_directory_(char_type const* directory, flags_type flags);
00289 
00292 private:
00293     const flags_type    m_flags;
00294     const string_type   m_directory;
00296 
00299 private:
00300     readdir_sequence(class_type const&);
00301     class_type& operator =(class_type const&);
00303 };
00304 
00312 class readdir_sequence::const_iterator
00313     : public stlsoft_ns_qual(iterator_base)<unixstl_ns_qual_std(input_iterator_tag)
00314                                         ,   readdir_sequence::value_type
00315                                         ,   us_ptrdiff_t
00316                                         ,   void                            
00317                                         ,   readdir_sequence::value_type    
00318                                         >
00319 {
00322 private:
00323     typedef readdir_sequence::string_type           string_type;
00324 public:
00326     typedef const_iterator                          class_type;
00328     typedef readdir_sequence::value_type            value_type;
00330     typedef readdir_sequence::flags_type            flags_type;
00331 
00332 
00334 
00337 private:
00338     friend class readdir_sequence;
00339 
00341     const_iterator(DIR *dir, string_type const& directory, flags_type flags);
00342 public:
00344     const_iterator();
00346     const_iterator(class_type const& rhs);
00348     ~const_iterator() stlsoft_throw_0();
00349 
00351     class_type const& operator =(class_type const& rhs);
00353 
00356 public:
00358     value_type operator *() const;
00359 
00362     class_type& operator ++();
00363 
00369     class_type operator ++(int);
00370 
00376     bool equal(class_type const& rhs) const;
00378 
00381 private:
00382     struct shared_handle;
00383 
00384     shared_handle   *m_handle;  
00385     struct dirent   *m_entry;   
00386     flags_type      m_flags;    
00387     string_type     m_scratch;  
00388     size_type       m_dirLen;   
00390 };
00391 
00392 #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
00393 struct readdir_sequence::const_iterator::shared_handle
00394 {
00397 public:
00398     typedef shared_handle   class_type;
00399     typedef DIR*            handle_type;
00401 
00404 public:
00405     handle_type m_dir;
00406 private:
00407     ss_sint32_t m_refCount;
00409 
00412 public:
00413     ss_explicit_k shared_handle(handle_type h)
00414         : m_dir(h)
00415         , m_refCount(1)
00416     {}
00417     ss_sint32_t AddRef()
00418     {
00419         return ++m_refCount;
00420     }
00421     ss_sint32_t Release()
00422     {
00423         ss_sint32_t rc = --m_refCount;
00424 
00425         if(0 == rc)
00426         {
00427             delete this;
00428         }
00429 
00430         return rc;
00431     }
00432 #if defined(STLSOFT_CF_COMPILER_WARNS_NO_PUBLIC_DTOR)
00433 protected:
00434 #else 
00435 private:
00436 #endif 
00437     ~shared_handle() stlsoft_throw_0()
00438     {
00439         UNIXSTL_MESSAGE_ASSERT("Shared search handle being destroyed with outstanding references!", 0 == m_refCount);
00440 
00441         if(NULL != m_dir)
00442         {
00443             ::closedir(m_dir);
00444         }
00445     }
00447 
00450 private:
00451     shared_handle(class_type const&);
00452     class_type& operator =(class_type const&);
00454 };
00455 #endif 
00456 
00458 
00459 
00460 inline us_bool_t operator ==(   readdir_sequence::const_iterator const& lhs
00461                             ,   readdir_sequence::const_iterator const& rhs)
00462 {
00463     return lhs.equal(rhs);
00464 }
00465 
00466 inline us_bool_t operator !=(   readdir_sequence::const_iterator const& lhs
00467                             ,   readdir_sequence::const_iterator const& rhs)
00468 {
00469     return !lhs.equal(rhs);
00470 }
00471 
00473 
00474 
00475 #ifdef STLSOFT_UNITTEST
00476 # include "./unittest/readdir_sequence_unittest_.h"
00477 #endif 
00478 
00479 
00480 
00481 
00482 
00483 #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
00484 
00485 
00486 
00487 inline  readdir_sequence::flags_type readdir_sequence::validate_flags_(readdir_sequence::flags_type flags)
00488 {
00489     const flags_type    validFlags  =   0
00490                                     |   includeDots
00491                                     |   directories
00492                                     |   files
00493                                     |   fullPath
00494                                     |   absolutePath
00495                                     |   0;
00496 
00497     UNIXSTL_MESSAGE_ASSERT("Specification of unrecognised/unsupported flags", flags == (flags & validFlags));
00498     STLSOFT_SUPPRESS_UNUSED(validFlags);
00499 
00500     if(0 == (flags & (directories | files)))
00501     {
00502         flags |= (directories | files);
00503     }
00504 
00505     return flags;
00506 }
00507 
00508 inline  readdir_sequence::string_type readdir_sequence::prepare_directory_(char_type const* directory, readdir_sequence::flags_type flags)
00509 {
00510     if( NULL == directory ||
00511         '\0' == *directory)
00512     {
00513         static const char_type  s_thisDir[] = { '.', '\0' };
00514 
00515         directory = s_thisDir;
00516     }
00517 
00518     basic_file_path_buffer<char_type>   path;
00519     size_type                           n;
00520 
00521     if(absolutePath & flags)
00522     {
00523         n = traits_type::get_full_path_name(directory, path.size(), &path[0]);
00524 
00525         if(0 == n)
00526         {
00527 #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
00528             STLSOFT_THROW_X(readdir_sequence_exception("Failed to enumerate directory", errno));
00529 #else 
00530             traits_type::str_n_copy(&path[0], directory, path.size());
00531 #endif 
00532         }
00533     }
00534     else
00535     {
00536         n = traits_type::str_len(directory);
00537 
00538         traits_type::char_copy(&path[0], directory, n);
00539         path[n] = '\0';
00540     }
00541 
00542     traits_type::ensure_dir_end(&path[n - 1]);
00543 
00544     directory = path.c_str();
00545 
00546     return directory;
00547 }
00548 
00549 inline readdir_sequence::const_iterator readdir_sequence::begin() const
00550 {
00551     DIR *dir = ::opendir(m_directory.c_str());
00552 
00553     if(NULL == dir)
00554     {
00555 #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
00556         STLSOFT_THROW_X(readdir_sequence_exception("Failed to enumerate directory", errno));
00557 #else 
00558         return const_iterator();
00559 #endif 
00560     }
00561 
00562 #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
00563     try
00564     {
00565 #endif 
00566         return const_iterator(dir, m_directory, m_flags);
00567 #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
00568     }
00569     catch(...)
00570     {
00571         ::closedir(dir);
00572 
00573         throw;
00574     }
00575 #endif 
00576 }
00577 
00578 inline readdir_sequence::const_iterator readdir_sequence::end() const
00579 {
00580     return const_iterator();
00581 }
00582 
00583 inline us_bool_t readdir_sequence::empty() const
00584 {
00585     return begin() != end();
00586 }
00587 
00588 inline readdir_sequence::string_type const& readdir_sequence::get_directory() const
00589 {
00590     return m_directory;
00591 }
00592 
00593 inline readdir_sequence::flags_type readdir_sequence::get_flags() const
00594 {
00595     return m_flags;
00596 }
00597 
00598 
00599 
00600 
00601 inline readdir_sequence::const_iterator::const_iterator(DIR *dir, readdir_sequence::string_type const& directory, readdir_sequence::flags_type flags)
00602     : m_handle(new shared_handle(dir))
00603     , m_entry(NULL)
00604     , m_flags(flags)
00605     , m_scratch(directory)
00606     , m_dirLen(directory.length())
00607 {
00608     UNIXSTL_ASSERT(traits_type::has_dir_end(m_scratch.c_str()));
00609 
00610     if(NULL == m_handle)
00611     {
00612         ::closedir(dir);
00613     }
00614     else
00615     {
00616         operator ++();
00617     }
00618 }
00619 
00620 inline readdir_sequence::const_iterator::const_iterator()
00621     : m_handle(NULL)
00622     , m_entry(NULL)
00623     , m_flags(0)
00624     , m_scratch()
00625     , m_dirLen(0)
00626 {}
00627 
00628 inline readdir_sequence::const_iterator::const_iterator(class_type const& rhs)
00629     : m_handle(rhs.m_handle)
00630     , m_entry(rhs.m_entry)
00631     , m_flags(rhs.m_flags)
00632     , m_scratch(rhs.m_scratch)
00633     , m_dirLen(rhs.m_dirLen)
00634 {
00635     if(NULL != m_handle)
00636     {
00637         m_handle->AddRef();
00638     }
00639 }
00640 
00641 inline readdir_sequence::const_iterator::~const_iterator() stlsoft_throw_0()
00642 {
00643     if(NULL != m_handle)
00644     {
00645         m_handle->Release();
00646     }
00647 }
00648 
00649 inline readdir_sequence::const_iterator::class_type const& readdir_sequence::const_iterator::operator =(readdir_sequence::const_iterator::class_type const& rhs)
00650 {
00651     shared_handle   *this_handle    =   m_handle;
00652 
00653     m_handle  =   rhs.m_handle;
00654     m_entry   =   rhs.m_entry;
00655     m_flags   =   rhs.m_flags;
00656     m_scratch =   rhs.m_scratch;
00657     m_dirLen  =   rhs.m_dirLen;
00658 
00659     if(NULL != m_handle)
00660     {
00661         m_handle->AddRef();
00662     }
00663 
00664     if(NULL != this_handle)
00665     {
00666         this_handle->Release();
00667     }
00668 
00669     return *this;
00670 }
00671 
00672 inline readdir_sequence::const_iterator::value_type readdir_sequence::const_iterator::operator *() const
00673 {
00674     UNIXSTL_MESSAGE_ASSERT( "Dereferencing invalid iterator", NULL != m_entry);
00675 
00676 #if defined(UNIXSTL_READDIR_SEQUENCE_OLD_VALUE_TYPE)
00677     return m_entry;
00678 #else 
00679     return (readdir_sequence::fullPath & m_flags) ? m_scratch.c_str() : m_entry->d_name;
00680 #endif 
00681 }
00682 
00683 inline readdir_sequence::const_iterator::class_type& readdir_sequence::const_iterator::operator ++()
00684 {
00685     UNIXSTL_MESSAGE_ASSERT( "Incrementing invalid iterator", NULL != m_handle);
00686 
00687     for(;;)
00688     {
00689         errno = 0;
00690 
00691         m_entry = ::readdir(m_handle->m_dir);
00692 
00693         if(NULL == m_entry)
00694         {
00695             if(0 != errno)
00696             {
00697 #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
00698                 STLSOFT_THROW_X(readdir_sequence_exception("Partial failure of directory enumeration", errno));
00699 #endif 
00700             }
00701         }
00702         else
00703         {
00704             UNIXSTL_ASSERT(NULL != m_entry->d_name);
00705 
00706             if(0 == (m_flags & includeDots))
00707             {
00708                 if(traits_type::is_dots(m_entry->d_name))
00709                 {
00710                     continue; 
00711                 }
00712             }
00713 
00714             
00715             
00716             
00717             
00718             
00719             
00720             if((m_flags & (fullPath | directories | files)) != (directories | files))
00721             {
00722                 
00723                 m_scratch.resize(m_dirLen);
00724                 
00725                 m_scratch += m_entry->d_name;
00726             }
00727 
00728             if((m_flags & (directories | files)) != (directories | files))
00729             {
00730                 
00731                 traits_type::stat_data_type st;
00732 
00733                 if(!traits_type::stat(m_scratch.c_str(), &st))
00734                 {
00735                     
00736                     
00737                     continue;
00738                 }
00739                 else
00740                 {
00741                     if(m_flags & directories) 
00742                     {
00743                         if(traits_type::is_directory(&st))
00744                         {
00745                             
00746                             break;
00747                         }
00748                     }
00749                     if(m_flags & files) 
00750                     {
00751                         if(traits_type::is_file(&st))
00752                         {
00753                             
00754                             break;
00755                         }
00756                     }
00757 
00758                     continue; 
00759                 }
00760             }
00761         }
00762 
00763         break;
00764     }
00765 
00766     if(NULL == m_entry)
00767     {
00768         UNIXSTL_ASSERT(NULL != m_handle);
00769 
00770         m_handle->Release();
00771 
00772         m_handle = NULL;
00773     }
00774 
00775     return *this;
00776 }
00777 
00778 inline readdir_sequence::const_iterator::class_type readdir_sequence::const_iterator::operator ++(int)
00779 {
00780     class_type  ret(*this);
00781 
00782     operator ++();
00783 
00784     return ret;
00785 }
00786 
00787 inline bool readdir_sequence::const_iterator::equal(readdir_sequence::const_iterator::class_type const& rhs) const
00788 {
00789     UNIXSTL_ASSERT(NULL == m_handle || NULL == rhs.m_handle || m_handle->m_dir == rhs.m_handle->m_dir);
00790 
00791     return m_entry == rhs.m_entry;
00792 }
00793 
00794 #endif 
00795 
00796 
00797 
00798 #ifndef _UNIXSTL_NO_NAMESPACE
00799 # if defined(_STLSOFT_NO_NAMESPACE) || \
00800      defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
00801 } 
00802 # else
00803 } 
00804 } 
00805 # endif 
00806 #endif 
00807 
00808 
00809 
00810 #endif 
00811 
00812