You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

910 lines
26 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: unixstl/filesystem/readdir_sequence.hpp
  3. *
  4. * Purpose: readdir_sequence class.
  5. *
  6. * Created: 15th January 2002
  7. * Updated: 17th August 2012
  8. *
  9. * Home: http://stlsoft.org/
  10. *
  11. * Copyright (c) 2002-2012, Matthew Wilson and Synesis Software
  12. * All rights reserved.
  13. *
  14. * Redistribution and use in source and binary forms, with or without
  15. * modification, are permitted provided that the following conditions are met:
  16. *
  17. * - Redistributions of source code must retain the above copyright notice, this
  18. * list of conditions and the following disclaimer.
  19. * - Redistributions in binary form must reproduce the above copyright notice,
  20. * this list of conditions and the following disclaimer in the documentation
  21. * and/or other materials provided with the distribution.
  22. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  23. * any contributors may be used to endorse or promote products derived from
  24. * this software without specific prior written permission.
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  27. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  30. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  31. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  32. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  33. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  34. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  35. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36. * POSSIBILITY OF SUCH DAMAGE.
  37. *
  38. * ////////////////////////////////////////////////////////////////////// */
  39. /** \file unixstl/filesystem/readdir_sequence.hpp
  40. *
  41. * \brief [C++ only] Definition of the unixstl::readdir_sequence class
  42. * (\ref group__library__filesystem "File System" Library).
  43. */
  44. #ifndef UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_READDIR_SEQUENCE
  45. #define UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_READDIR_SEQUENCE
  46. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  47. # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_READDIR_SEQUENCE_MAJOR 5
  48. # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_READDIR_SEQUENCE_MINOR 2
  49. # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_READDIR_SEQUENCE_REVISION 1
  50. # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_READDIR_SEQUENCE_EDIT 134
  51. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  52. /* /////////////////////////////////////////////////////////////////////////
  53. * Includes
  54. */
  55. #ifndef UNIXSTL_INCL_UNIXSTL_H_UNIXSTL
  56. # include <unixstl/unixstl.h>
  57. #endif /* !UNIXSTL_INCL_UNIXSTL_H_UNIXSTL */
  58. #ifndef UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS
  59. # include <unixstl/filesystem/filesystem_traits.hpp>
  60. #endif /* !UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS */
  61. #ifndef UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_FILE_PATH_BUFFER
  62. # include <unixstl/filesystem/file_path_buffer.hpp>
  63. #endif /* !UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_FILE_PATH_BUFFER */
  64. #ifndef UNIXSTL_INCL_UNIXSTL_HPP_ERROR_UNIX_EXCEPTIONS
  65. # include <unixstl/error/exceptions.hpp>
  66. #endif /* !UNIXSTL_INCL_UNIXSTL_ERROR_HPP_UNIX_EXCEPTIONS */
  67. #if defined(PATH_MAX)
  68. # ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_STATIC_STRING
  69. # include <stlsoft/string/static_string.hpp>
  70. # endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_STATIC_STRING */
  71. #else /* ? PATH_MAX */
  72. # ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_SIMPLE_STRING
  73. # include <stlsoft/string/simple_string.hpp>
  74. # endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_SIMPLE_STRING */
  75. #endif /* !PATH_MAX */
  76. #ifndef STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER
  77. # include <stlsoft/util/std/iterator_helper.hpp>
  78. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER */
  79. #ifndef STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS
  80. # include <stlsoft/collections/util/collections.hpp>
  81. #endif /* !STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS */
  82. #ifndef STLSOFT_INCL_H_UNISTD
  83. # define STLSOFT_INCL_H_UNISTD
  84. # include <unistd.h>
  85. #endif /* !STLSOFT_INCL_H_UNISTD */
  86. #ifndef STLSOFT_INCL_SYS_H_TYPES
  87. # define STLSOFT_INCL_SYS_H_TYPES
  88. # include <sys/types.h>
  89. #endif /* !STLSOFT_INCL_SYS_H_TYPES */
  90. #ifndef STLSOFT_INCL_SYS_H_STAT
  91. # define STLSOFT_INCL_SYS_H_STAT
  92. # include <sys/stat.h>
  93. #endif /* !STLSOFT_INCL_SYS_H_STAT */
  94. #ifndef STLSOFT_INCL_H_DIRENT
  95. # define STLSOFT_INCL_H_DIRENT
  96. # include <dirent.h>
  97. #endif /* !STLSOFT_INCL_H_DIRENT */
  98. /* /////////////////////////////////////////////////////////////////////////
  99. * Namespace
  100. */
  101. /* No STLSoft namespaces means no UNIXSTL namespaces */
  102. #ifdef _STLSOFT_NO_NAMESPACES
  103. # define _UNIXSTL_NO_NAMESPACES
  104. #endif /* _STLSOFT_NO_NAMESPACES */
  105. /* No UNIXSTL namespaces means no unixstl namespace */
  106. #ifdef _UNIXSTL_NO_NAMESPACES
  107. # define _UNIXSTL_NO_NAMESPACE
  108. #endif /* _UNIXSTL_NO_NAMESPACES */
  109. #ifndef _UNIXSTL_NO_NAMESPACE
  110. # if defined(_STLSOFT_NO_NAMESPACE) || \
  111. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  112. /* There is no stlsoft namespace, so must define ::unixstl */
  113. namespace unixstl
  114. {
  115. # else
  116. /* Define stlsoft::unixstl_project */
  117. namespace stlsoft
  118. {
  119. namespace unixstl_project
  120. {
  121. # endif /* _STLSOFT_NO_NAMESPACE */
  122. #endif /* !_UNIXSTL_NO_NAMESPACE */
  123. /* /////////////////////////////////////////////////////////////////////////
  124. * Classes
  125. */
  126. /** \brief Exception class thrown by unixstl::readdir_sequence.
  127. *
  128. * \ingroup group__library__filesystem
  129. */
  130. class readdir_sequence_exception
  131. : public unix_exception
  132. {
  133. /// \name Types
  134. /// @{
  135. public:
  136. typedef unix_exception parent_class_type;
  137. typedef readdir_sequence_exception class_type;
  138. typedef parent_class_type::string_type string_type;
  139. /// @}
  140. /// \name Construction
  141. /// @{
  142. public:
  143. readdir_sequence_exception(us_char_a_t const* message, us_int_t erno)
  144. : parent_class_type(message, erno)
  145. , Directory()
  146. {}
  147. readdir_sequence_exception(us_char_a_t const* message, us_int_t erno, us_char_a_t const* directory)
  148. : parent_class_type(message, erno)
  149. #if 0
  150. , Directory(directory)
  151. #else /* ? 0 */
  152. , Directory(stlsoft::c_str_ptr(directory))
  153. #endif /* 0 */
  154. {}
  155. ~readdir_sequence_exception() stlsoft_throw_0()
  156. {}
  157. private:
  158. class_type& operator =(class_type const&);
  159. /// @}
  160. /// \name Fields
  161. /// @{
  162. public:
  163. /// The name of this field is subject to change in a future revision
  164. string_type const Directory;
  165. /// @}
  166. };
  167. /** \brief STL-like readonly sequence based on directory contents
  168. *
  169. * \ingroup group__library__filesystem
  170. *
  171. * This class presents and STL-like readonly sequence interface to allow the
  172. * iteration over the contents of a directory.
  173. */
  174. class readdir_sequence
  175. : public stlsoft_ns_qual(stl_collection_tag)
  176. {
  177. /// \name Member Types
  178. /// @{
  179. public:
  180. /// \brief This class
  181. typedef readdir_sequence class_type;
  182. private:
  183. // These make it easy to move to a template, if ever needed
  184. typedef us_char_a_t char_type;
  185. typedef filesystem_traits<char_type> traits_type;
  186. public:
  187. /// \brief The size type
  188. typedef us_size_t size_type;
  189. /// \brief The non-mutating (const) iterator type
  190. class const_iterator;
  191. /// \brief The value type
  192. #if defined(UNIXSTL_READDIR_SEQUENCE_OLD_VALUE_TYPE)
  193. typedef struct dirent const* value_type;
  194. #else /* ? UNIXSTL_READDIR_SEQUENCE_OLD_VALUE_TYPE */
  195. typedef char_type const* value_type;
  196. #endif /* UNIXSTL_READDIR_SEQUENCE_OLD_VALUE_TYPE */
  197. /// \brief The flags type
  198. typedef us_int_t flags_type;
  199. public:
  200. #if defined(PATH_MAX)
  201. typedef stlsoft_ns_qual(basic_static_string)< char_type
  202. , PATH_MAX
  203. > string_type;
  204. #else /* ? PATH_MAX */
  205. typedef stlsoft_ns_qual(basic_simple_string)< char_type
  206. > string_type;
  207. #endif /* !PATH_MAX */
  208. /// @}
  209. /// \name Member Constants
  210. /// @{
  211. public:
  212. enum
  213. {
  214. includeDots = 0x0008 /*!< \brief Requests that dots directories be included in the returned sequence */
  215. , directories = 0x0010 /*!< \brief Causes the search to include directories */
  216. , files = 0x0020 /*!< \brief Causes the search to include files */
  217. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  218. , sockets = 0x0000 /*!< CURRENTLY UNSUPPORTED : DO NOT USE! This exists for forward compatibility with STLSoft 1.10 test programs, and is subject to change in the future. A future version will support sockets, but it may not use this enumerator name. */
  219. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  220. , typeMask = 0x0070
  221. , fullPath = 0x0100 /*!< \brief Each file entry is presented as a full path relative to the search directory. */
  222. , absolutePath = 0x0200 /*!< \brief The search directory is converted to an absolute path. */
  223. };
  224. /// @}
  225. /// \name Construction
  226. /// @{
  227. public:
  228. /// \brief Constructs a sequence according to the given criteria
  229. ///
  230. /// The constructor initialises a readdir_sequence instance on the given
  231. /// directory with the given flags.
  232. ///
  233. /// \param directory The directory whose contents are to be searched
  234. /// \param flags Flags to alter the behaviour of the search
  235. ///
  236. /// \note The \c flags parameter defaults to <code>directories | files</code> because
  237. /// this reflects the default behaviour of \c readdir(), and also because it is the
  238. /// most efficient.
  239. template <ss_typename_param_k S>
  240. readdir_sequence(S const& directory, flags_type flags = directories | files)
  241. : m_flags(validate_flags_(flags))
  242. , m_directory(prepare_directory_(stlsoft_ns_qual(c_str_ptr)(directory), flags))
  243. {}
  244. /// @}
  245. /// \name Iteration
  246. /// @{
  247. public:
  248. /// \brief Begins the iteration
  249. ///
  250. /// \return An iterator representing the start of the sequence
  251. const_iterator begin() const;
  252. /// \brief Ends the iteration
  253. ///
  254. /// \return An iterator representing the end of the sequence
  255. const_iterator end() const;
  256. /// @}
  257. /// \name Attributes
  258. /// @{
  259. public:
  260. /// \brief Indicates whether the search sequence is empty
  261. us_bool_t empty() const;
  262. /// \brief The search directory
  263. ///
  264. /// \note The value returned by this method always has a trailing path name separator, so
  265. /// you can safely concatenate this with the value returned by the iterator's operator *()
  266. /// with minimal fuss.
  267. string_type const& get_directory() const;
  268. /// \brief The flags used by the sequence
  269. ///
  270. /// \note This value is the value used by the sequence, which may, as a result of the
  271. /// determination of defaults, be different from those specified in its constructor. In
  272. /// other words, if <code>includeDots</code> is specified, this function
  273. /// will return <code>includeDots | directories | files</code>
  274. flags_type get_flags() const;
  275. /// @}
  276. /// \name Implementation
  277. /// @{
  278. private:
  279. /// \brief Ensures that the flags are correct
  280. static flags_type validate_flags_(flags_type flags);
  281. /// \brief Prepares the directory, according to the given flags
  282. static string_type prepare_directory_(char_type const* directory, flags_type flags);
  283. /// @}
  284. /// \name Members
  285. /// @{
  286. private:
  287. const flags_type m_flags;
  288. const string_type m_directory;
  289. /// @}
  290. /// \name Not to be implemented
  291. /// @{
  292. private:
  293. readdir_sequence(class_type const&);
  294. class_type& operator =(class_type const&);
  295. /// @}
  296. };
  297. /** \brief Iterator for the \link unixstl::readdir_sequence readdir_sequence\endlink class.
  298. *
  299. * \ingroup group__library__filesystem
  300. *
  301. * This class performs as a non-mutating iterator (aka const iterator) for the
  302. * readdir_sequence class.
  303. */
  304. class readdir_sequence::const_iterator
  305. : public stlsoft_ns_qual(iterator_base)<unixstl_ns_qual_std(input_iterator_tag)
  306. , readdir_sequence::value_type
  307. , us_ptrdiff_t
  308. , void // By-Value Temporary reference
  309. , readdir_sequence::value_type // By-Value Temporary reference
  310. >
  311. {
  312. /// \name Members
  313. /// @{
  314. private:
  315. typedef readdir_sequence::string_type string_type;
  316. public:
  317. /// \brief The class type
  318. typedef const_iterator class_type;
  319. /// \brief The value type
  320. typedef readdir_sequence::value_type value_type;
  321. /// \brief The flags type
  322. typedef readdir_sequence::flags_type flags_type;
  323. // typedef value_type* pointer;
  324. // typedef value_type& reference;
  325. /// @}
  326. /// \name Construction
  327. /// @{
  328. private:
  329. friend class readdir_sequence;
  330. /// \brief Construct an instance and begin a sequence iteration on the given dir.
  331. const_iterator(DIR* dir, string_type const& directory, flags_type flags);
  332. public:
  333. /// \brief Default constructor
  334. const_iterator();
  335. /// \brief Copy constructor
  336. const_iterator(class_type const& rhs);
  337. /// \brief Release the search handle
  338. ~const_iterator() stlsoft_throw_0();
  339. /// \brief Copy assignment operator
  340. class_type const& operator =(class_type const& rhs);
  341. /// @}
  342. /// \name Input Iterator Methods
  343. /// @{
  344. public:
  345. /// \brief Returns the value representative
  346. value_type operator *() const;
  347. /// \brief Moves the iteration on to the next point in the sequence, or end() if
  348. /// the sequence is exhausted
  349. class_type& operator ++();
  350. /// \brief Post-increment form of operator ++().
  351. ///
  352. /// \note Because this version uses a temporary on which to call the
  353. /// pre-increment form it is thereby less efficient, and should not be used
  354. /// except where post-increment semantics are required.
  355. class_type operator ++(int);
  356. /// \brief Compares \c this for equality with \c rhs
  357. ///
  358. /// \param rhs The instance against which to test
  359. /// \retval true if the iterators are equivalent
  360. /// \retval false if the iterators are not equivalent
  361. bool equal(class_type const& rhs) const;
  362. /// @}
  363. /// \name Members
  364. /// @{
  365. private:
  366. struct shared_handle;
  367. shared_handle* m_handle; // The DIR handle, shared with other iterator instances
  368. struct dirent* m_entry; // The current entry
  369. flags_type m_flags; // flags. (Only non-const, to allow copy assignment)
  370. string_type m_scratch; // Holds the directory, and is a scratch area
  371. size_type m_dirLen; // The length of the directory
  372. /// @}
  373. };
  374. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  375. struct readdir_sequence::const_iterator::shared_handle
  376. {
  377. /// \name Member Types
  378. /// @{
  379. public:
  380. typedef shared_handle class_type;
  381. typedef DIR* handle_type;
  382. /// @}
  383. /// \name Members
  384. /// @{
  385. public:
  386. handle_type m_dir;
  387. private:
  388. ss_sint32_t m_refCount;
  389. /// @}
  390. /// \name Construction
  391. /// @{
  392. public:
  393. ss_explicit_k shared_handle(handle_type h)
  394. : m_dir(h)
  395. , m_refCount(1)
  396. {}
  397. ss_sint32_t AddRef()
  398. {
  399. return ++m_refCount;
  400. }
  401. ss_sint32_t Release()
  402. {
  403. ss_sint32_t rc = --m_refCount;
  404. if(0 == rc)
  405. {
  406. delete this;
  407. }
  408. return rc;
  409. }
  410. #if defined(STLSOFT_CF_COMPILER_WARNS_NO_PUBLIC_DTOR)
  411. protected:
  412. #else /* ? STLSOFT_CF_COMPILER_WARNS_NO_PUBLIC_DTOR */
  413. private:
  414. #endif /* STLSOFT_CF_COMPILER_WARNS_NO_PUBLIC_DTOR */
  415. ~shared_handle() stlsoft_throw_0()
  416. {
  417. UNIXSTL_MESSAGE_ASSERT("Shared search handle being destroyed with outstanding references!", 0 == m_refCount);
  418. if(NULL != m_dir)
  419. {
  420. ::closedir(m_dir);
  421. }
  422. }
  423. /// @}
  424. /// \name Not to be implemented
  425. /// @{
  426. private:
  427. shared_handle(class_type const&);
  428. class_type& operator =(class_type const&);
  429. /// @}
  430. };
  431. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  432. ////////////////////////////////////////////////////////////////////////////
  433. // Operators
  434. inline
  435. us_bool_t
  436. operator ==(
  437. readdir_sequence::const_iterator const& lhs
  438. , readdir_sequence::const_iterator const& rhs
  439. )
  440. {
  441. return lhs.equal(rhs);
  442. }
  443. inline
  444. us_bool_t
  445. operator !=(
  446. readdir_sequence::const_iterator const& lhs
  447. , readdir_sequence::const_iterator const& rhs
  448. )
  449. {
  450. return !lhs.equal(rhs);
  451. }
  452. ////////////////////////////////////////////////////////////////////////////
  453. // Unit-testing
  454. #ifdef STLSOFT_UNITTEST
  455. # include "./unittest/readdir_sequence_unittest_.h"
  456. #endif /* STLSOFT_UNITTEST */
  457. /* /////////////////////////////////////////////////////////////////////////
  458. * Implementation
  459. */
  460. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  461. // readdir_sequence
  462. inline
  463. /* static */
  464. readdir_sequence::flags_type
  465. readdir_sequence::validate_flags_(
  466. readdir_sequence::flags_type flags
  467. )
  468. {
  469. const flags_type validFlags = 0
  470. | includeDots
  471. | 0
  472. | directories
  473. | files
  474. | 0
  475. | fullPath
  476. | absolutePath
  477. | 0;
  478. UNIXSTL_MESSAGE_ASSERT("Specification of unrecognised/unsupported flags", flags == (flags & validFlags));
  479. STLSOFT_SUPPRESS_UNUSED(validFlags);
  480. if(0 == (flags & (directories | files)))
  481. {
  482. flags |= (directories | files);
  483. }
  484. return flags;
  485. }
  486. inline
  487. /* static */
  488. readdir_sequence::string_type
  489. readdir_sequence::prepare_directory_(
  490. char_type const* directory
  491. , readdir_sequence::flags_type flags
  492. )
  493. {
  494. if( NULL == directory ||
  495. '\0' == *directory)
  496. {
  497. static const char_type s_thisDir[] = { '.', '\0' };
  498. directory = s_thisDir;
  499. }
  500. basic_file_path_buffer<char_type> path;
  501. size_type n;
  502. if(absolutePath & flags)
  503. {
  504. n = traits_type::get_full_path_name(directory, path.size() - 1u, &path[0]);
  505. if(0 == n)
  506. {
  507. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  508. STLSOFT_THROW_X(readdir_sequence_exception("Failed to enumerate directory", errno, directory));
  509. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  510. traits_type::char_copy(&path[0], directory, n);
  511. path[n] = \'0';
  512. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  513. }
  514. }
  515. else
  516. {
  517. n = traits_type::str_len(directory);
  518. traits_type::char_copy(&path[0], directory, n);
  519. path[n] = '\0';
  520. }
  521. traits_type::ensure_dir_end(&path[n - 1]);
  522. directory = path.c_str();
  523. return directory;
  524. }
  525. inline
  526. readdir_sequence::const_iterator
  527. readdir_sequence::begin() const
  528. {
  529. DIR* dir = ::opendir(m_directory.c_str());
  530. if(NULL == dir)
  531. {
  532. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  533. STLSOFT_THROW_X(readdir_sequence_exception("Failed to enumerate directory", errno, m_directory.c_str()));
  534. #else /* ? STLSOFT_CF_EXCEPTION_SUPPORT */
  535. return const_iterator();
  536. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  537. }
  538. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  539. try
  540. {
  541. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  542. return const_iterator(dir, m_directory, m_flags);
  543. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  544. }
  545. catch(...)
  546. {
  547. ::closedir(dir);
  548. throw;
  549. }
  550. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  551. }
  552. inline
  553. readdir_sequence::const_iterator
  554. readdir_sequence::end() const
  555. {
  556. return const_iterator();
  557. }
  558. inline
  559. us_bool_t
  560. readdir_sequence::empty() const
  561. {
  562. return begin() != end();
  563. }
  564. inline
  565. readdir_sequence::string_type const&
  566. readdir_sequence::get_directory() const
  567. {
  568. return m_directory;
  569. }
  570. inline
  571. readdir_sequence::flags_type
  572. readdir_sequence::get_flags() const
  573. {
  574. return m_flags;
  575. }
  576. // readdir_sequence::const_iterator;
  577. inline
  578. readdir_sequence::const_iterator::const_iterator(
  579. DIR* dir
  580. , readdir_sequence::string_type const& directory
  581. , readdir_sequence::flags_type flags
  582. )
  583. : m_handle(new shared_handle(dir))
  584. , m_entry(NULL)
  585. , m_flags(flags)
  586. , m_scratch(directory)
  587. , m_dirLen(directory.length())
  588. {
  589. UNIXSTL_ASSERT(traits_type::has_dir_end(m_scratch.c_str()));
  590. if(NULL == m_handle)
  591. {
  592. ::closedir(dir);
  593. }
  594. else
  595. {
  596. operator ++();
  597. }
  598. }
  599. inline
  600. readdir_sequence::const_iterator::const_iterator()
  601. : m_handle(NULL)
  602. , m_entry(NULL)
  603. , m_flags(0)
  604. , m_scratch()
  605. , m_dirLen(0)
  606. {}
  607. inline
  608. readdir_sequence::const_iterator::const_iterator(
  609. class_type const& rhs
  610. )
  611. : m_handle(rhs.m_handle)
  612. , m_entry(rhs.m_entry)
  613. , m_flags(rhs.m_flags)
  614. , m_scratch(rhs.m_scratch)
  615. , m_dirLen(rhs.m_dirLen)
  616. {
  617. if(NULL != m_handle)
  618. {
  619. m_handle->AddRef();
  620. }
  621. }
  622. inline
  623. readdir_sequence::const_iterator::~const_iterator() stlsoft_throw_0()
  624. {
  625. if(NULL != m_handle)
  626. {
  627. m_handle->Release();
  628. }
  629. }
  630. inline
  631. readdir_sequence::const_iterator::class_type const&
  632. readdir_sequence::const_iterator::operator =(
  633. readdir_sequence::const_iterator::class_type const& rhs
  634. )
  635. {
  636. shared_handle* this_handle = m_handle;
  637. m_handle = rhs.m_handle;
  638. m_entry = rhs.m_entry;
  639. m_flags = rhs.m_flags;
  640. m_scratch = rhs.m_scratch;
  641. m_dirLen = rhs.m_dirLen;
  642. if(NULL != m_handle)
  643. {
  644. m_handle->AddRef();
  645. }
  646. if(NULL != this_handle)
  647. {
  648. this_handle->Release();
  649. }
  650. return *this;
  651. }
  652. inline
  653. readdir_sequence::const_iterator::value_type
  654. readdir_sequence::const_iterator::operator *() const
  655. {
  656. UNIXSTL_MESSAGE_ASSERT( "Dereferencing invalid iterator", NULL != m_entry);
  657. #if defined(UNIXSTL_READDIR_SEQUENCE_OLD_VALUE_TYPE)
  658. return m_entry;
  659. #else /* ? UNIXSTL_READDIR_SEQUENCE_OLD_VALUE_TYPE */
  660. return (readdir_sequence::fullPath & m_flags) ? m_scratch.c_str() : m_entry->d_name;
  661. #endif /* UNIXSTL_READDIR_SEQUENCE_OLD_VALUE_TYPE */
  662. }
  663. inline
  664. readdir_sequence::const_iterator::class_type&
  665. readdir_sequence::const_iterator::operator ++()
  666. {
  667. UNIXSTL_MESSAGE_ASSERT( "Incrementing invalid iterator", NULL != m_handle);
  668. for(;;)
  669. {
  670. errno = 0;
  671. m_entry = ::readdir(m_handle->m_dir);
  672. if(NULL == m_entry)
  673. {
  674. if(0 != errno)
  675. {
  676. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  677. m_scratch.resize(m_dirLen);
  678. STLSOFT_THROW_X(readdir_sequence_exception("Partial failure of directory enumeration", errno, m_scratch.c_str()));
  679. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  680. }
  681. }
  682. else
  683. {
  684. UNIXSTL_ASSERT(NULL != m_entry->d_name);
  685. // Check for dots
  686. if(0 == (m_flags & includeDots))
  687. {
  688. if(traits_type::is_dots(m_entry->d_name))
  689. {
  690. continue; // Don't want dots; skip it
  691. }
  692. }
  693. // If either
  694. //
  695. // - eliding files or directories, or
  696. // - requiring absolute path
  697. //
  698. // then need to construct it.
  699. #ifdef _WIN32
  700. if((m_flags & (fullPath | directories | files)) != (directories | files))
  701. #endif /* _WIN32 */
  702. {
  703. // Truncate the scratch to the directory path, ...
  704. m_scratch.resize(m_dirLen);
  705. // ... and add the file
  706. m_scratch += m_entry->d_name;
  707. }
  708. #ifdef _WIN32
  709. if((m_flags & (directories | files)) != (directories | files))
  710. #endif /* _WIN32 */
  711. {
  712. // Now need to process the file, by using stat
  713. traits_type::stat_data_type st;
  714. if(!traits_type::stat(m_scratch.c_str(), &st))
  715. {
  716. // Failed to get info from entry. Must assume it is
  717. // dead, so skip it
  718. continue;
  719. }
  720. else
  721. {
  722. #ifndef _WIN32
  723. // Test for sockets : this version does not support sockets,
  724. // but does elide them from the search results.
  725. if(traits_type::is_socket(&st))
  726. {
  727. continue;
  728. }
  729. #endif /* !_WIN32 */
  730. if(m_flags & directories) // Want directories
  731. {
  732. if(traits_type::is_directory(&st))
  733. {
  734. // It is a directory, so accept it
  735. break;
  736. }
  737. }
  738. if(m_flags & files) // Want files
  739. {
  740. if(traits_type::is_file(&st))
  741. {
  742. // It is a file, so accept it
  743. break;
  744. }
  745. }
  746. continue; // Not a match, so skip this entry
  747. }
  748. }
  749. }
  750. break;
  751. }
  752. if(NULL == m_entry)
  753. {
  754. UNIXSTL_ASSERT(NULL != m_handle);
  755. m_handle->Release();
  756. m_handle = NULL;
  757. }
  758. return *this;
  759. }
  760. inline
  761. readdir_sequence::const_iterator::class_type
  762. readdir_sequence::const_iterator::operator ++(int)
  763. {
  764. class_type ret(*this);
  765. operator ++();
  766. return ret;
  767. }
  768. inline
  769. bool
  770. readdir_sequence::const_iterator::equal(
  771. readdir_sequence::const_iterator::class_type const& rhs
  772. ) const
  773. {
  774. UNIXSTL_ASSERT(NULL == m_handle || NULL == rhs.m_handle || m_handle->m_dir == rhs.m_handle->m_dir);
  775. return m_entry == rhs.m_entry;
  776. }
  777. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  778. /* ////////////////////////////////////////////////////////////////////// */
  779. #ifndef _UNIXSTL_NO_NAMESPACE
  780. # if defined(_STLSOFT_NO_NAMESPACE) || \
  781. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  782. } // namespace unixstl
  783. # else
  784. } // namespace unixstl_project
  785. } // namespace stlsoft
  786. # endif /* _STLSOFT_NO_NAMESPACE */
  787. #endif /* !_UNIXSTL_NO_NAMESPACE */
  788. /* ////////////////////////////////////////////////////////////////////// */
  789. #endif /* !UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_READDIR_SEQUENCE */
  790. /* ///////////////////////////// end of file //////////////////////////// */