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