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.

1361 lines
46 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: unixstl/filesystem/glob_sequence.hpp
  3. *
  4. * Purpose: glob_sequence class.
  5. *
  6. * Created: 15th January 2002
  7. * Updated: 4th June 2012
  8. *
  9. * Thanks: To Carlos Santander Bernal for helping with Mac compatibility.
  10. * To Nevin Liber for pressing upon me the need to lead by
  11. * example when writing books about good design/implementation.
  12. *
  13. * Home: http://stlsoft.org/
  14. *
  15. * Copyright (c) 2002-2012, Matthew Wilson and Synesis Software
  16. * All rights reserved.
  17. *
  18. * Redistribution and use in source and binary forms, with or without
  19. * modification, are permitted provided that the following conditions are met:
  20. *
  21. * - Redistributions of source code must retain the above copyright notice, this
  22. * list of conditions and the following disclaimer.
  23. * - Redistributions in binary form must reproduce the above copyright notice,
  24. * this list of conditions and the following disclaimer in the documentation
  25. * and/or other materials provided with the distribution.
  26. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  27. * any contributors may be used to endorse or promote products derived from
  28. * this software without specific prior written permission.
  29. *
  30. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  31. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  32. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  34. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  35. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  36. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  37. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  38. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  39. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  40. * POSSIBILITY OF SUCH DAMAGE.
  41. *
  42. * ////////////////////////////////////////////////////////////////////// */
  43. /** \file unixstl/filesystem/glob_sequence.hpp
  44. *
  45. * \brief [C++ only] Definition of the unixstl::glob_sequence class
  46. * (\ref group__library__filesystem "File System" Library).
  47. */
  48. #ifndef UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_GLOB_SEQUENCE
  49. #define UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_GLOB_SEQUENCE
  50. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  51. # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_GLOB_SEQUENCE_MAJOR 5
  52. # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_GLOB_SEQUENCE_MINOR 2
  53. # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_GLOB_SEQUENCE_REVISION 5
  54. # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_GLOB_SEQUENCE_EDIT 159
  55. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  56. /* /////////////////////////////////////////////////////////////////////////
  57. * Includes
  58. */
  59. #ifndef UNIXSTL_INCL_UNIXSTL_H_UNIXSTL
  60. # include <unixstl/unixstl.h>
  61. #endif /* !UNIXSTL_INCL_UNIXSTL_H_UNIXSTL */
  62. #ifndef UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS
  63. # include <unixstl/filesystem/filesystem_traits.hpp>
  64. #endif /* !UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS */
  65. #ifndef UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_FILE_PATH_BUFFER
  66. # include <unixstl/filesystem/file_path_buffer.hpp>
  67. #endif /* !UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_FILE_PATH_BUFFER */
  68. #ifndef STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER
  69. # include <stlsoft/util/std/iterator_helper.hpp>
  70. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER */
  71. #ifndef STLSOFT_INCL_STLSOFT_MEMORY_HPP_AUTO_BUFFER
  72. # include <stlsoft/memory/auto_buffer.hpp>
  73. #endif /* !STLSOFT_INCL_STLSOFT_MEMORY_HPP_AUTO_BUFFER */
  74. #ifndef STLSOFT_INCL_STLSOFT_MEMORY_HPP_ALLOCATOR_SELECTOR
  75. # include <stlsoft/memory/allocator_selector.hpp>
  76. #endif /* !STLSOFT_INCL_STLSOFT_MEMORY_HPP_ALLOCATOR_SELECTOR */
  77. #ifndef STLSOFT_INCL_STLSOFT_SMARTPTR_HPP_SCOPED_HANDLE
  78. # include <stlsoft/smartptr/scoped_handle.hpp>
  79. #endif /* !STLSOFT_INCL_STLSOFT_SMARTPTR_HPP_SCOPED_HANDLE */
  80. #ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_TOKENISER_FUNCTIONS
  81. //# include <stlsoft/string/tokeniser_functions.hpp> // for find_next_token
  82. #endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_TOKENISER_FUNCTIONS */
  83. #ifndef STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS
  84. # include <stlsoft/collections/util/collections.hpp>
  85. #endif /* !STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS */
  86. #ifndef STLSOFT_INCL_STLSOFT_UTIL_HPP_STD_SWAP
  87. # include <stlsoft/util/std_swap.hpp>
  88. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_HPP_STD_SWAP */
  89. #ifndef STLSOFT_INCL_SYS_H_TYPES
  90. # define STLSOFT_INCL_SYS_H_TYPES
  91. # include <sys/types.h>
  92. #endif /* !STLSOFT_INCL_SYS_H_TYPES */
  93. #ifndef STLSOFT_INCL_SYS_H_STAT
  94. # define STLSOFT_INCL_SYS_H_STAT
  95. # include <sys/stat.h> // for stat()
  96. #endif /* !STLSOFT_INCL_SYS_H_STAT */
  97. #ifndef STLSOFT_INCL_H_ERRNO
  98. # define STLSOFT_INCL_H_ERRNO
  99. # include <errno.h>
  100. #endif /* !STLSOFT_INCL_H_ERRNO */
  101. #ifndef STLSOFT_INCL_H_GLOB
  102. # define STLSOFT_INCL_H_GLOB
  103. # include <glob.h> // for glob(), globfree()
  104. #endif /* !STLSOFT_INCL_H_GLOB */
  105. #ifndef STLSOFT_INCL_ALGORITHM
  106. # define STLSOFT_INCL_ALGORITHM
  107. # include <algorithm> // for std::sort
  108. #endif /* !STLSOFT_INCL_ALGORITHM */
  109. #ifndef STLSOFT_INCL_EXCEPTION
  110. # define STLSOFT_INCL_EXCEPTION
  111. # include <exception> // for std::exception
  112. #endif /* !STLSOFT_INCL_EXCEPTION */
  113. #ifndef STLSOFT_INCL_STDEXCEPT
  114. # define STLSOFT_INCL_STDEXCEPT
  115. # include <stdexcept> // for std::runtime_error
  116. #endif /* !STLSOFT_INCL_STDEXCEPT */
  117. #ifdef STLSOFT_UNITTEST
  118. # include <stlsoft/string/simple_string.hpp>
  119. #endif /* STLSOFT_UNITTEST */
  120. /* /////////////////////////////////////////////////////////////////////////
  121. * Library compatibility
  122. */
  123. /* User may define UNIXSTL_GLOB_SEQUENCE_TRUST_ONLYDIR to cause the
  124. * component to trust GLOB_ONLYDIR, if present. If GLOB_ONLYDIR is not
  125. * detected, UNIXSTL_GLOB_SEQUENCE_TRUST_ONLYDIR is ignored.
  126. *
  127. * For any implementations that
  128. */
  129. #ifndef GLOB_ONLYDIR
  130. # ifdef UNIXSTL_GLOB_SEQUENCE_TRUST_ONLYDIR
  131. # undef UNIXSTL_GLOB_SEQUENCE_TRUST_ONLYDIR
  132. # endif /* UNIXSTL_GLOB_SEQUENCE_TRUST_ONLYDIR */
  133. #endif /* GLOB_ONLYDIR */
  134. /* User may define UNIXSTL_GLOB_SEQUENCE_TRUST_ONLYREG to cause the
  135. * component to trust GLOB_ONLYREG, if present. If GLOB_ONLYREG is not
  136. * detected, UNIXSTL_GLOB_SEQUENCE_TRUST_ONLYREG is ignored.
  137. */
  138. #ifndef GLOB_ONLYREG
  139. # ifdef UNIXSTL_GLOB_SEQUENCE_TRUST_ONLYREG
  140. # undef UNIXSTL_GLOB_SEQUENCE_TRUST_ONLYREG
  141. # endif /* UNIXSTL_GLOB_SEQUENCE_TRUST_ONLYREG */
  142. #endif /* GLOB_ONLYREG */
  143. /* User may define UNIXSTL_GLOB_SEQUENCE_TRUST_NODOTSDIRS to cause the
  144. * component to trust GLOB_NODOTSDIRS, if present. If GLOB_NODOTSDIRS is
  145. * not detected, UNIXSTL_GLOB_SEQUENCE_TRUST_NODOTSDIRS is ignored.
  146. */
  147. #ifndef GLOB_NODOTSDIRS
  148. # ifdef UNIXSTL_GLOB_SEQUENCE_TRUST_NODOTSDIRS
  149. # undef UNIXSTL_GLOB_SEQUENCE_TRUST_NODOTSDIRS
  150. # endif /* UNIXSTL_GLOB_SEQUENCE_TRUST_NODOTSDIRS */
  151. #endif /* GLOB_NODOTSDIRS */
  152. /* User may define UNIXSTL_GLOB_SEQUENCE_DONT_TRUST_MARK do prevent the
  153. * component from trusting GLOB_MARK; this is meaningless on non-Windows
  154. * systems, since marking cannot be trusted to filter for files by eliding
  155. * directories because entries may also be sockets, etc.
  156. */
  157. #ifndef _WIN32
  158. # ifndef UNIXSTL_GLOB_SEQUENCE_DONT_TRUST_MARK
  159. # define UNIXSTL_GLOB_SEQUENCE_DONT_TRUST_MARK
  160. # endif /* !UNIXSTL_GLOB_SEQUENCE_DONT_TRUST_MARK */
  161. #endif /* !_WIN32 */
  162. /* /////////////////////////////////////////////////////////////////////////
  163. * Compiler compatibility
  164. */
  165. #ifdef STLSOFT_DOCUMENTATION_SKIP_SECTION
  166. # define GLOB_SEQUENCE_CTOR_PRIMARY_FORM
  167. #elif defined(STLSOFT_COMPILER_IS_CUSTOM)
  168. # define GLOB_SEQUENCE_CTOR_PRIMARY_FORM
  169. #elif defined(STLSOFT_COMPILER_IS_UNKNOWN)
  170. # define GLOB_SEQUENCE_CTOR_PRIMARY_FORM
  171. #elif defined(STLSOFT_COMPILER_IS_BORLAND)
  172. # define GLOB_SEQUENCE_CTOR_OLD_FORM
  173. #elif defined(STLSOFT_COMPILER_IS_COMO)
  174. # define GLOB_SEQUENCE_CTOR_PRIMARY_FORM
  175. #elif defined(STLSOFT_COMPILER_IS_DMC)
  176. # define GLOB_SEQUENCE_CTOR_PRIMARY_FORM
  177. #elif defined(STLSOFT_COMPILER_IS_GCC)
  178. # define GLOB_SEQUENCE_CTOR_PRIMARY_FORM
  179. #elif defined(STLSOFT_COMPILER_IS_INTEL)
  180. # define GLOB_SEQUENCE_CTOR_PRIMARY_FORM
  181. #elif defined(STLSOFT_COMPILER_IS_MSVC)
  182. # if _MSC_VER >= 1310
  183. # define GLOB_SEQUENCE_CTOR_PRIMARY_FORM
  184. # elif _MSC_VER >= 1020
  185. # define GLOB_SEQUENCE_CTOR_ALT_FORM
  186. # else /* ? compiler */
  187. # define GLOB_SEQUENCE_CTOR_OLD_FORM
  188. # endif /* compiler */
  189. #elif defined(STLSOFT_COMPILER_IS_MWERKS)
  190. # define GLOB_SEQUENCE_CTOR_ALT_FORM
  191. #elif defined(STLSOFT_COMPILER_IS_VECTORC)
  192. # define GLOB_SEQUENCE_CTOR_ALT_FORM
  193. #elif defined(STLSOFT_COMPILER_IS_WATCOM)
  194. # define GLOB_SEQUENCE_CTOR_OLD_FORM
  195. #else /* ? compiler */
  196. # error Unrecognised compiler
  197. #endif /* compiler */
  198. /* /////////////////////////////////////////////////////////////////////////
  199. * Namespace
  200. */
  201. #ifndef _UNIXSTL_NO_NAMESPACE
  202. # if defined(_STLSOFT_NO_NAMESPACE) || \
  203. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  204. /* There is no stlsoft namespace, so must define ::unixstl */
  205. namespace unixstl
  206. {
  207. # else
  208. /* Define stlsoft::unixstl_project */
  209. namespace stlsoft
  210. {
  211. namespace unixstl_project
  212. {
  213. # endif /* _STLSOFT_NO_NAMESPACE */
  214. #endif /* !_UNIXSTL_NO_NAMESPACE */
  215. /* /////////////////////////////////////////////////////////////////////////
  216. * Classes
  217. */
  218. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  219. /** \brief The exception-type thrown by unixstl::glob_sequence
  220. *
  221. * \ingroup group__library__filesystem
  222. */
  223. class glob_sequence_exception
  224. #if defined(STLSOFT_COMPILER_IS_DMC)
  225. : public std::exception
  226. #else /* ? compiler */
  227. : public unixstl_ns_qual_std(exception)
  228. #endif /* compiler */
  229. {
  230. /// \name Types
  231. /// @{
  232. public:
  233. #if defined(STLSOFT_COMPILER_IS_DMC)
  234. typedef std::exception parent_class_type;
  235. #else /* ? compiler */
  236. typedef unixstl_ns_qual_std(exception) parent_class_type;
  237. #endif /* compiler */
  238. typedef glob_sequence_exception class_type;
  239. /// @}
  240. /// \name Construction
  241. /// @{
  242. public:
  243. ss_explicit_k glob_sequence_exception(us_int_t globStatus, us_int_t errno_) stlsoft_throw_0()
  244. : m_globStatus(globStatus)
  245. , m_errno(errno_)
  246. {}
  247. /// @}
  248. /// \name Accessors
  249. /// @{
  250. public:
  251. #if defined(STLSOFT_COMPILER_IS_DMC)
  252. char const* what() const throw()
  253. #else /* ? compiler */
  254. char const* what() const stlsoft_throw_0()
  255. #endif /* compiler */
  256. {
  257. return "glob_sequence failure";
  258. }
  259. us_int_t get_globstatus() const stlsoft_throw_0()
  260. {
  261. return m_globStatus;
  262. }
  263. us_int_t get_errno() const stlsoft_throw_0()
  264. {
  265. return m_errno;
  266. }
  267. /// @}
  268. /// \name Members
  269. /// @{
  270. private:
  271. us_int_t const m_globStatus;
  272. us_int_t const m_errno;
  273. /// @}
  274. /// \name Not to be implemented
  275. /// @{
  276. private:
  277. class_type& operator =(class_type const&);
  278. /// @}
  279. };
  280. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  281. /** \brief STL-like readonly sequence based on the results of file-system wildcard matches
  282. *
  283. * \ingroup group__library__filesystem
  284. *
  285. * This class presents and STL-like readonly sequence interface to allow the
  286. * iteration over the results of file-system wildcard matches.
  287. */
  288. class glob_sequence
  289. : public stlsoft_ns_qual(stl_collection_tag)
  290. {
  291. /// \name Types
  292. /// @{
  293. public:
  294. /// \brief This class
  295. typedef glob_sequence class_type;
  296. /// \brief The char type
  297. typedef us_char_a_t char_type;
  298. // The traits type
  299. typedef filesystem_traits<char_type> traits_type;
  300. /// \brief The value type
  301. typedef char_type const* value_type;
  302. /// \brief The non-mutating (const) reference type
  303. typedef value_type const& const_reference;
  304. /// \brief The non-mutating (const) pointer type
  305. typedef value_type const* const_pointer;
  306. /// \brief The size type
  307. typedef us_size_t size_type;
  308. /// \brief The difference type
  309. typedef us_ptrdiff_t difference_type;
  310. /// \brief The allocator type
  311. typedef stlsoft_ns_qual(allocator_selector)<value_type>::allocator_type allocator_type;
  312. /// \brief The non-mutating (const) iterator type
  313. typedef stlsoft_ns_qual(pointer_iterator)< value_type const
  314. , const_pointer
  315. , const_reference
  316. >::type const_iterator;
  317. #ifdef STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT
  318. /// \brief The type of the const (non-mutating) reverse iterator
  319. typedef stlsoft_ns_qual(reverse_iterator_base) < const_iterator
  320. , value_type
  321. , const_reference
  322. , const_pointer
  323. , difference_type
  324. > const_reverse_iterator;
  325. #endif /* STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
  326. /// @}
  327. /// \name Member Constants
  328. /// @{
  329. public:
  330. enum search_flags
  331. {
  332. includeDots = 0x0008 /*!< \brief Requests that dots directories be included in the returned sequence for wildcard patterns, for which \c matchPeriod must also be specified (if GLOB_PERIOD is defined). Always ignored unless \c directories is specified. */
  333. , directories = 0x0010 /*!< \brief Causes the search to include directories */
  334. , files = 0x0020 /*!< \brief Causes the search to include files */
  335. , noSort = 0x0100 /*!< \brief Does not sort entries. Corresponds to GLOB_NOSORT. */
  336. , markDirs = 0x0200 /*!< \brief Mark directories with a trailing path name separator. Corresponds to GLOB_MARK. */
  337. , absolutePath = 0x0400 /*!< \brief Return all entries in absolute format. Ignored when a dots directory is specified as the pattern. Note, absolute paths may not always be in canonical form, e.g. '/user/me/.' if specify ('/user/me', '.', absolutePath), in which case the caller is responsible for obtaining canonical form. */
  338. , breakOnError = 0x0800 /*!< \brief Causes processing to stop on the first filesystem error. Corresponds to GLOB_ERR. */
  339. , noEscape = 0x1000 /*!< \brief Treats backslashes literally. Corresponds to GLOB_NOESCAPE. */
  340. #ifdef GLOB_PERIOD
  341. , matchPeriod = 0x2000 /*!< \brief Leading '.' can be matched by metacharacters. Corresponds to GLOB_PERIOD. */
  342. #endif /* GLOB_PERIOD */
  343. #ifdef GLOB_BRACE
  344. , bracePatterns = 0x4000 /*!< \brief Allow "{*.cpp;makefile*}" style multi-part patterns. Corresponds to GLOB_BRACE. */
  345. #endif /* GLOB_BRACE */
  346. #ifdef GLOB_TILDE
  347. , expandTilde = 0x8000 /*!< \brief Expand ~ and ~<user> directories. Corresponds to GLOB_TILDE. */
  348. #endif /* GLOB_TILDE */
  349. };
  350. /// @}
  351. /// \name Construction
  352. /// @{
  353. public:
  354. #if defined(GLOB_SEQUENCE_CTOR_PRIMARY_FORM)
  355. /// \brief Constructs a sequence according to the given criteria
  356. ///
  357. /// The constructor initialises a glob_sequence instance on the given
  358. /// pattern with the given flags.
  359. ///
  360. /// \param pattern The pattern against which to match the file-system contents
  361. /// \param flags Flags to alter the behaviour of the search
  362. ///
  363. /// \note If exceptions are supported, then this will throw a glob_sequence_exception
  364. /// on failure of any underlying functions
  365. template<ss_typename_param_k S>
  366. ss_explicit_k glob_sequence(S const& pattern, us_int_t flags = files | directories)
  367. : m_flags(validate_flags_(flags))
  368. , m_buffer(1)
  369. {
  370. m_cItems = init_glob_(NULL, stlsoft_ns_qual(c_str_ptr)(pattern));
  371. UNIXSTL_ASSERT(is_valid());
  372. }
  373. # ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  374. template<ss_typename_param_k S>
  375. glob_sequence(S const& pattern, search_flags flag)
  376. : m_flags(validate_flags_(flag))
  377. , m_buffer(1)
  378. {
  379. m_cItems = init_glob_(NULL, stlsoft_ns_qual(c_str_ptr)(pattern));
  380. UNIXSTL_ASSERT(is_valid());
  381. }
  382. # endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  383. /// \brief Constructs a sequence according to the given criteria
  384. ///
  385. /// The constructor initialises a glob_sequence instance on the given
  386. /// pattern with the given flags.
  387. ///
  388. /// \param directory The directory in which the pattern is located
  389. /// \param pattern The pattern against which to match the file-system contents
  390. /// \param flags Flags to alter the behaviour of the search
  391. ///
  392. /// \note If exceptions are supported, then this will throw a glob_sequence_exception
  393. /// on failure of any underlying functions
  394. template< ss_typename_param_k S1
  395. , ss_typename_param_k S2
  396. >
  397. glob_sequence(S1 const& directory, S2 const& pattern, us_int_t flags = files | directories)
  398. : m_flags(validate_flags_(flags))
  399. , m_buffer(1)
  400. {
  401. m_cItems = init_glob_(stlsoft_ns_qual(c_str_ptr)(directory), stlsoft_ns_qual(c_str_ptr)(pattern));
  402. UNIXSTL_ASSERT(is_valid());
  403. }
  404. # ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  405. template< ss_typename_param_k S1
  406. , ss_typename_param_k S2
  407. >
  408. glob_sequence(S1 const& directory, S2 const& pattern, search_flags flag)
  409. : m_flags(validate_flags_(flag))
  410. , m_buffer(1)
  411. {
  412. m_cItems = init_glob_(stlsoft_ns_qual(c_str_ptr)(directory), stlsoft_ns_qual(c_str_ptr)(pattern));
  413. UNIXSTL_ASSERT(is_valid());
  414. }
  415. # endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  416. #elif defined(GLOB_SEQUENCE_CTOR_ALT_FORM)
  417. template<ss_typename_param_k S>
  418. ss_explicit_k glob_sequence(S const& pattern)
  419. : m_flags(validate_flags_(files | directories))
  420. , m_buffer(1)
  421. {
  422. m_cItems = init_glob_(NULL, stlsoft_ns_qual(c_str_ptr)(pattern));
  423. UNIXSTL_ASSERT(is_valid());
  424. }
  425. template<ss_typename_param_k S>
  426. glob_sequence(S const& pattern, us_int_t flags)
  427. : m_flags(validate_flags_(flags))
  428. , m_buffer(1)
  429. {
  430. m_cItems = init_glob_(NULL, stlsoft_ns_qual(c_str_ptr)(pattern));
  431. UNIXSTL_ASSERT(is_valid());
  432. }
  433. glob_sequence(char_type const* directory, char_type const* pattern, us_int_t flags = files | directories);
  434. template<ss_typename_param_k S>
  435. glob_sequence(S const& directory, char const* pattern, us_int_t flags = files | directories)
  436. : m_flags(validate_flags_(flags))
  437. , m_buffer(1)
  438. {
  439. m_cItems = init_glob_(stlsoft_ns_qual(c_str_ptr)(directory), stlsoft_ns_qual(c_str_ptr)(pattern));
  440. UNIXSTL_ASSERT(is_valid());
  441. }
  442. template<ss_typename_param_k S>
  443. glob_sequence(S const& directory, S const& pattern, us_int_t flags = files | directories)
  444. : m_flags(validate_flags_(flags))
  445. , m_buffer(1)
  446. {
  447. m_cItems = init_glob_(stlsoft_ns_qual(c_str_ptr)(directory), stlsoft_ns_qual(c_str_ptr)(pattern));
  448. UNIXSTL_ASSERT(is_valid());
  449. }
  450. #elif defined(GLOB_SEQUENCE_CTOR_OLD_FORM)
  451. ss_explicit_k glob_sequence(char_type const* pattern, us_int_t flags = files | directories);
  452. glob_sequence(char_type const* directory, char_type const* pattern, us_int_t flags = files | directories);
  453. #else /* ? constructor form */
  454. # error Constructor form not recognised
  455. #endif /* constructor form */
  456. #if 0
  457. /// \brief Constructs a sequence according to the given criteria
  458. ///
  459. /// The constructor initialises a glob_sequence instance on the given
  460. /// pattern with the given flags.
  461. ///
  462. /// \param directory The directory in which the pattern is located
  463. /// \param pattern The pattern against which to match the file-system contents
  464. /// \param flags Flags to alter the behaviour of the search
  465. ///
  466. /// \note If exceptions are supported, then this will throw a glob_sequence_exception
  467. /// on failure of any underlying functions
  468. glob_sequence(char_type const* directory, char_type const* pattern, char_type delim, us_int_t flags = files | directories);
  469. #endif /* 0 */
  470. /// \brief Releases any acquired resources
  471. ~glob_sequence() stlsoft_throw_0();
  472. /// @}
  473. /// \name Attributes
  474. /// @{
  475. public:
  476. /// \brief Returns the number of elements in the sequence
  477. us_size_t size() const;
  478. /// \brief Indicates whether the search sequence is empty
  479. us_bool_t empty() const;
  480. /// @}
  481. /// \name Element Access
  482. /// @{
  483. public:
  484. /// \brief Returns the value corresponding to the given index
  485. ///
  486. /// \note In debug-mode a runtime assert is applied to enforce that the index is valid. There is <b>no</b> release-time checking on the index validity!
  487. const_reference operator [](size_type index) const;
  488. /// @}
  489. /// \name Iteration
  490. /// @{
  491. public:
  492. /// \brief Begins the iteration
  493. ///
  494. /// \return An iterator representing the start of the sequence
  495. const_iterator begin() const;
  496. /// \brief Ends the iteration
  497. ///
  498. /// \return An iterator representing the end of the sequence
  499. const_iterator end() const;
  500. #ifdef STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT
  501. /// \brief Begins the reverse iteration
  502. ///
  503. /// \return An iterator representing the start of the reverse sequence
  504. const_reverse_iterator rbegin() const;
  505. /// \brief Ends the reverse iteration
  506. ///
  507. /// \return An iterator representing the end of the reverse sequence
  508. const_reverse_iterator rend() const;
  509. #endif /* STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
  510. /// @}
  511. /// \name Implementation
  512. /// @{
  513. private:
  514. // Tests the class invariant
  515. us_bool_t is_valid() const;
  516. // Validates the flags, and sets up defaults
  517. static us_int_t validate_flags_(us_int_t flags);
  518. // Returns true if pch is a path separator "/" (or "\\"); false otherwise
  519. static us_bool_t is_path_separator_(char_type ch);
  520. // Returns true if pch == "" or "/" (or "\\"); false otherwise
  521. static us_bool_t is_end_of_path_elements_(char_type const* pch, difference_type index);
  522. // Returns true if s points to a path that is a dots directory; false otherwise
  523. static us_bool_t is_dots_maybe_slashed_(char_type const* s, us_bool_t* bTwoDots);
  524. // Calls glob() and process the results
  525. //
  526. // init_glob_() - handles any directory and/or pattern (where the pattern may contain rel/abs dir)
  527. // init_glob_1_() - splits combined path into directory+pattern (which are passed to init_glob_2_())
  528. // init_glob_2_() - handles receives properly split directory+pattern (and does test in order to call init_glob_3_())
  529. // init_glob_3_() - handles full pattern, with bool indicating whether pattern contains wildcard at leaf
  530. us_size_t init_glob_(char_type const* directory, char_type const* pattern);
  531. us_size_t init_glob_1_(size_type bufferSize, char_type* combinedPath);
  532. us_size_t init_glob_2_(char_type const* patternDir, char_type const* pattern0);
  533. us_size_t init_glob_3_(char_type const* pattern, bool isPattern0Wild);
  534. /// @}
  535. /// \name Members
  536. /// @{
  537. private:
  538. typedef stlsoft_ns_qual(auto_buffer_old)< char_type const*
  539. , allocator_type
  540. , 128
  541. > buffer_type_;
  542. us_int_t const m_flags;
  543. char_type const** m_base;
  544. us_size_t m_cItems;
  545. buffer_type_ m_buffer;
  546. glob_t m_glob;
  547. /// @}
  548. /// \name Not to be implemented
  549. /// @{
  550. private:
  551. glob_sequence(class_type const&);
  552. class_type const& operator =(class_type const&);
  553. /// @}
  554. };
  555. ////////////////////////////////////////////////////////////////////////////
  556. // Unit-testing
  557. #ifdef STLSOFT_UNITTEST
  558. # include "./unittest/glob_sequence_unittest_.h"
  559. #endif /* STLSOFT_UNITTEST */
  560. /* /////////////////////////////////////////////////////////////////////////
  561. * Implementation
  562. */
  563. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  564. #if defined(GLOB_SEQUENCE_CTOR_OLD_FORM)
  565. inline /* ss_explicit_k */ glob_sequence::glob_sequence(glob_sequence::char_type const* pattern, us_int_t flags)
  566. : m_flags(validate_flags_(flags))
  567. , m_buffer(1)
  568. {
  569. m_cItems = init_glob_(NULL, pattern);
  570. UNIXSTL_ASSERT(is_valid());
  571. }
  572. #endif /* GLOB_SEQUENCE_CTOR_OLD_FORM */
  573. #if defined(GLOB_SEQUENCE_CTOR_OLD_FORM) || \
  574. defined(GLOB_SEQUENCE_CTOR_ALT_FORM)
  575. inline glob_sequence::glob_sequence(glob_sequence::char_type const* directory, glob_sequence::char_type const* pattern, us_int_t flags)
  576. : m_flags(validate_flags_(flags))
  577. , m_buffer(1)
  578. {
  579. m_cItems = init_glob_(directory, pattern);
  580. UNIXSTL_ASSERT(is_valid());
  581. }
  582. #endif /* GLOB_SEQUENCE_CTOR_OLD_FORM || GLOB_SEQUENCE_CTOR_ALT_FORM */
  583. #if 0
  584. template< ss_typename_param_k S1
  585. , ss_typename_param_k S2
  586. >
  587. inline glob_sequence::glob_sequence(S1 const& directory, S2 const& pattern, us_int_t flags)
  588. : m_flags(validate_flags_(flags))
  589. , m_buffer(1)
  590. {
  591. m_cItems = init_glob_(stlsoft_ns_qual(c_str_ptr)(directory), stlsoft_ns_qual(c_str_ptr)(pattern));
  592. UNIXSTL_ASSERT(is_valid());
  593. }
  594. #endif /* 0 */
  595. #if 0
  596. inline glob_sequence::glob_sequence(char_type const* directory, char_type const* pattern, char_type delim, us_int_t flags)
  597. : m_flags(validate_flags_(flags))
  598. , m_buffer(1)
  599. {
  600. m_cItems = init_glob_(directory, pattern);
  601. UNIXSTL_ASSERT(is_valid());
  602. }
  603. #endif /* 0 */
  604. inline glob_sequence::~glob_sequence() stlsoft_throw_0()
  605. {
  606. UNIXSTL_ASSERT(is_valid());
  607. if(NULL != m_base)
  608. {
  609. ::globfree(&m_glob);
  610. }
  611. }
  612. inline us_size_t glob_sequence::size() const
  613. {
  614. return m_cItems;
  615. }
  616. inline us_bool_t glob_sequence::empty() const
  617. {
  618. return 0 == size();
  619. }
  620. inline glob_sequence::const_reference glob_sequence::operator [](glob_sequence::size_type index) const
  621. {
  622. UNIXSTL_MESSAGE_ASSERT("index access out of range in glob_sequence", index < 1 + size()); // Has to be +1, since legitimate to take address of one-past-the-end
  623. return m_base[index];
  624. }
  625. inline glob_sequence::const_iterator glob_sequence::begin() const
  626. {
  627. return m_base;
  628. }
  629. inline glob_sequence::const_iterator glob_sequence::end() const
  630. {
  631. return m_base + m_cItems;
  632. }
  633. #ifdef STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT
  634. inline glob_sequence::const_reverse_iterator glob_sequence::rbegin() const
  635. {
  636. return const_reverse_iterator(end());
  637. }
  638. inline glob_sequence::const_reverse_iterator glob_sequence::rend() const
  639. {
  640. return const_reverse_iterator(begin());
  641. }
  642. #endif /* STLSOFT_LF_BIDIRECTIONAL_ITERATOR_SUPPORT */
  643. inline us_bool_t glob_sequence::is_valid() const
  644. {
  645. if((0 != m_cItems) && (NULL == m_base))
  646. {
  647. return false;
  648. }
  649. return true;
  650. }
  651. inline /* static */ us_int_t glob_sequence::validate_flags_(us_int_t flags)
  652. {
  653. const us_int_t validFlags = 0
  654. | includeDots
  655. | directories
  656. | files
  657. | noSort
  658. | markDirs
  659. | absolutePath
  660. | breakOnError
  661. | noEscape
  662. #ifdef GLOB_PERIOD
  663. | matchPeriod
  664. #endif /* GLOB_PERIOD */
  665. #ifdef GLOB_BRACE
  666. | bracePatterns
  667. #endif /* GLOB_BRACE */
  668. #ifdef GLOB_TILDE
  669. | expandTilde
  670. #endif /* GLOB_TILDE */
  671. | 0;
  672. UNIXSTL_MESSAGE_ASSERT("Specification of unrecognised/unsupported flags", flags == (flags & validFlags));
  673. STLSOFT_SUPPRESS_UNUSED(validFlags);
  674. if(0 == (flags & (directories | files)))
  675. {
  676. flags |= (directories | files);
  677. }
  678. #ifndef UNIXSTL_GLOB_SEQUENCE_DONT_TRUST_MARK
  679. // If we're not searching for directories, then we can optimise the
  680. // subsequent filtering by asking for the dots directories (so we
  681. // skip that filtering) and asking for directories to be marked (so
  682. // we can detect the mark rather than making a system call (stat())
  683. if(0 == (flags & directories))
  684. {
  685. // It's more efficient to not bother doing a separate dots check if all
  686. // directories are being elided.
  687. flags |= includeDots;
  688. // Since we're not going to be returning directories to the caller, and
  689. // it's more efficient to believe the glob() directory marking rather
  690. // than calling stat, we add the markDirs flag here.
  691. flags |= markDirs;
  692. }
  693. #endif /* !UNIXSTL_GLOB_SEQUENCE_DONT_TRUST_MARK */
  694. return flags;
  695. }
  696. inline /* static */ us_bool_t glob_sequence::is_path_separator_(glob_sequence::char_type ch)
  697. {
  698. return ch == '/'
  699. #if defined(_UNIXSTL_COMPILER_IS_UNKNOWN) && \
  700. !defined(_UNIXSTL_GLOB_SEQUENCE_NO_BACK_SLASH_TERMINATOR)
  701. || ch == '\\' /* Allow for testing on Win32 systems */
  702. #endif /* _UNIXSTL_COMPILER_IS_UNKNOWN && !_UNIXSTL_GLOB_SEQUENCE_NO_BACK_SLASH_TERMINATOR */
  703. ;
  704. }
  705. inline /* static */ us_bool_t glob_sequence::is_end_of_path_elements_(glob_sequence::char_type const* pch, glob_sequence::difference_type index)
  706. {
  707. return pch[index] == '\0' ||
  708. ( pch[index + 1] == '\0' &&
  709. is_path_separator_(pch[index]));
  710. }
  711. inline /* static */ us_bool_t glob_sequence::is_dots_maybe_slashed_(glob_sequence::char_type const* s, us_bool_t* bTwoDots)
  712. {
  713. UNIXSTL_ASSERT(NULL != s);
  714. UNIXSTL_ASSERT(NULL != bTwoDots);
  715. // This must match all patterns like the following:
  716. //
  717. // "." l=1, s[0] = .
  718. // ".." l=2, s[0] = ., s[1] = .
  719. // "./" l=2, s[0] = ., s[1] = sep
  720. // "../" l=3, s[0] = ., s[1] = ., s[2] = sep
  721. // "abc/."
  722. // "abc/.."
  723. // "abc/./"
  724. // "abc/../"
  725. const us_size_t len = traits_type::str_len(s);
  726. us_size_t lastNameChar = len -1;
  727. UNIXSTL_ASSERT(len > 0);
  728. if(is_path_separator_(s[lastNameChar]))
  729. {
  730. --lastNameChar;
  731. }
  732. if('.' == s[lastNameChar])
  733. {
  734. if(0 == lastNameChar)
  735. {
  736. return true;
  737. }
  738. else
  739. {
  740. --lastNameChar;
  741. if( 0 == lastNameChar ||
  742. is_path_separator_(s[lastNameChar]))
  743. {
  744. *bTwoDots = false;
  745. return true;
  746. }
  747. else if( 0 < lastNameChar &&
  748. '.' == s[lastNameChar])
  749. {
  750. --lastNameChar;
  751. if( 0 == lastNameChar ||
  752. is_path_separator_(s[lastNameChar]))
  753. {
  754. *bTwoDots = true;
  755. return true;
  756. }
  757. else
  758. {
  759. return false;
  760. }
  761. }
  762. }
  763. }
  764. return false;
  765. }
  766. inline us_size_t glob_sequence::init_glob_(glob_sequence::char_type const* directory, glob_sequence::char_type const* pattern)
  767. {
  768. UNIXSTL_MESSAGE_ASSERT("Null pattern given to glob_sequence", NULL != pattern);
  769. char_type const* lastSlash = traits_type::find_last_path_name_separator(pattern);
  770. if(NULL == lastSlash)
  771. {
  772. // already properly separated
  773. return init_glob_2_(directory, pattern);
  774. }
  775. else
  776. {
  777. if(traits_type::is_path_rooted(pattern))
  778. {
  779. directory = NULL;
  780. }
  781. basic_file_path_buffer<char_type> scratch_; // Scratch buffer for directory + pattern
  782. size_type dirLen = (NULL == directory) ? 0u : traits_type::str_len(directory);
  783. size_type patLen = traits_type::str_len(pattern);
  784. if(0 != dirLen)
  785. {
  786. traits_type::char_copy(&scratch_[0] + 0, directory, dirLen);
  787. scratch_[dirLen] = '\0';
  788. dirLen += traits_type::str_len(traits_type::ensure_dir_end(&scratch_[0] + (dirLen - 1))) - 1;
  789. }
  790. traits_type::char_copy(&scratch_[0] + dirLen, pattern, patLen);
  791. scratch_[dirLen + patLen] = '\0';
  792. return init_glob_1_(scratch_.size(), scratch_.data());
  793. }
  794. }
  795. inline us_size_t glob_sequence::init_glob_1_(size_type bufferSize, char_type* combinedPath)
  796. {
  797. char_type const* const lastSlash = traits_type::find_last_path_name_separator(combinedPath);
  798. UNIXSTL_ASSERT(NULL != lastSlash);
  799. combinedPath[lastSlash - combinedPath] = '\0';
  800. char_type const* directory = combinedPath;
  801. char_type const* pattern = lastSlash + 1;
  802. return init_glob_2_(directory, pattern);
  803. }
  804. inline us_size_t glob_sequence::init_glob_2_(char_type const* directory, char_type const* pattern0)
  805. {
  806. // Preconditions:
  807. //
  808. // - pattern must not be NULL
  809. // - pattern must not contain a path-name separator
  810. UNIXSTL_ASSERT(NULL != pattern0);
  811. UNIXSTL_ASSERT(NULL == traits_type::str_chr(pattern0, '/'));
  812. #ifdef _WIN32
  813. UNIXSTL_ASSERT(NULL == traits_type::str_chr(pattern0, '\\'));
  814. #endif /* _WIN32 */
  815. static char_type const s_wildChars[] = { '?', '*', '\0' };
  816. us_bool_t const isPattern0Wild = (NULL != traits_type::str_pbrk(pattern0, s_wildChars));
  817. if( NULL != directory &&
  818. '\0' != directory[0])
  819. {
  820. if( absolutePath == (m_flags & absolutePath) &&
  821. !traits_type::is_path_rooted(directory))
  822. {
  823. us_bool_t const isPatternDirWild = (NULL != traits_type::str_pbrk(directory, s_wildChars));
  824. if(isPatternDirWild)
  825. {
  826. errno = EINVAL;
  827. m_base = NULL;
  828. return 0;
  829. }
  830. else
  831. {
  832. basic_file_path_buffer<char_type> scratch2_; // Scratch buffer for absolute path
  833. size_type absLen = traits_type::get_full_path_name(directory, scratch2_.size(), &scratch2_[0]);
  834. if(0 == absLen)
  835. {
  836. m_base = NULL;
  837. return 0;
  838. }
  839. else
  840. {
  841. return init_glob_2_(scratch2_.data(), pattern0);
  842. }
  843. }
  844. }
  845. else
  846. {
  847. basic_file_path_buffer<char_type> scratch_; // Scratch buffer for directory / pattern
  848. #ifndef STLSOFT_CF_EXCEPTION_SUPPORT
  849. if(0 == scratch_.size())
  850. {
  851. m_base = NULL;
  852. return 0;
  853. }
  854. else
  855. #endif /* !STLSOFT_CF_EXCEPTION_SUPPORT */
  856. {
  857. size_type dirLen = traits_type::str_len(directory);
  858. size_type patLen = traits_type::str_len(pattern0);
  859. traits_type::char_copy(&scratch_[0] + 0, directory, dirLen);
  860. scratch_[dirLen] = '\0';
  861. dirLen += traits_type::str_len(traits_type::ensure_dir_end(&scratch_[0] + (dirLen - 1))) - 1;
  862. traits_type::char_copy(&scratch_[0] + dirLen, pattern0, patLen);
  863. scratch_[dirLen + patLen] = '\0';
  864. return init_glob_3_(scratch_.c_str(), isPattern0Wild);
  865. }
  866. }
  867. }
  868. else
  869. {
  870. return init_glob_3_(pattern0, isPattern0Wild);
  871. }
  872. }
  873. inline us_size_t glob_sequence::init_glob_3_(char_type const* pattern, bool isPattern0Wild)
  874. {
  875. us_int_t glob_flags = 0;
  876. if(m_flags & noSort)
  877. {
  878. // Don't bother sorting
  879. glob_flags |= GLOB_NOSORT;
  880. }
  881. if(m_flags & markDirs)
  882. {
  883. // Ask for trailing slashes on directories
  884. glob_flags |= GLOB_MARK;
  885. }
  886. #ifdef UNIXSTL_GLOB_SEQUENCE_TRUST_ONLYDIR // If this is not defined, we rely on stat
  887. if(directories == (m_flags & (directories | files)))
  888. {
  889. // Ask for only directories
  890. glob_flags |= GLOB_ONLYDIR;
  891. }
  892. #endif /* UNIXSTL_GLOB_SEQUENCE_TRUST_ONLYDIR */
  893. #ifdef UNIXSTL_GLOB_SEQUENCE_TRUST_ONLYREG // If this is not defined, we rely on stat
  894. if(files == (m_flags & (directories | files)))
  895. {
  896. // Ask for only files
  897. glob_flags |= GLOB_ONLYREG;
  898. }
  899. #endif /* UNIXSTL_GLOB_SEQUENCE_TRUST_ONLYREG */
  900. #ifdef GLOB_ERR
  901. if(m_flags & breakOnError)
  902. {
  903. glob_flags |= GLOB_ERR;
  904. }
  905. #endif /* GLOB_ERR */
  906. #ifdef GLOB_NOESCAPE
  907. if(m_flags & noEscape)
  908. {
  909. glob_flags |= GLOB_NOESCAPE;
  910. }
  911. #endif /* GLOB_NOESCAPE */
  912. #ifdef GLOB_PERIOD
  913. if(m_flags & matchPeriod)
  914. {
  915. glob_flags |= GLOB_PERIOD;
  916. }
  917. #endif /* GLOB_PERIOD */
  918. #ifdef GLOB_BRACE
  919. if(m_flags & bracePatterns)
  920. {
  921. glob_flags |= GLOB_BRACE;
  922. }
  923. #endif /* GLOB_BRACE */
  924. #ifdef GLOB_TILDE
  925. if(m_flags & expandTilde)
  926. {
  927. glob_flags |= GLOB_TILDE;
  928. }
  929. #endif /* GLOB_TILDE */
  930. #ifdef UNIXSTL_GLOB_SEQUENCE_TRUST_NODOTSDIRS
  931. if(0 == (m_flags & includeDots))
  932. {
  933. glob_flags |= GLOB_NODOTSDIRS;
  934. }
  935. #endif /* UNIXSTL_GLOB_SEQUENCE_TRUST_NODOTSDIRS */
  936. int gr = ::glob(pattern, glob_flags, NULL, &m_glob);
  937. if(0 != gr)
  938. {
  939. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  940. # ifdef GLOB_NOMATCH
  941. // When GLOB_NOMATCH is not defined, we can reasonably infer that
  942. // there is no replacement value, so throwing on a non-zero
  943. // return from glob() is appropriate
  944. if(GLOB_NOMATCH != gr)
  945. # endif /* GLOB_NOMATCH */
  946. {
  947. STLSOFT_THROW_X(glob_sequence_exception(gr, 0));
  948. }
  949. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  950. m_base = NULL;
  951. return 0;
  952. }
  953. else
  954. {
  955. // Sink the glob_t instance into a local scoped_handle, to invoke
  956. // ::globfree() automatically if we encounter any problems during
  957. // the processing. At the end we'll call detach(), to "give it"
  958. // to the glob_sequence instance.
  959. stlsoft_ns_qual(scoped_handle)<glob_t*> cleanup(&m_glob, ::globfree);
  960. char_type** base = m_glob.gl_pathv;
  961. us_size_t cItems = static_cast<us_size_t>(m_glob.gl_pathc);
  962. // This section performs a COW on the entry pointers, into
  963. // the m_buffer member, if any of the following hold:
  964. //
  965. // 1. we're eliding dots
  966. // 2. we want directories only, and so will need to
  967. // remove files, AND we do not trust GLOB_ONLYDIR
  968. // 3. we want files only, and so will need
  969. // to remove directories
  970. //
  971. bool const elidingDots = isPattern0Wild && (0 == (m_flags & includeDots));
  972. if( elidingDots || // 1
  973. #ifndef UNIXSTL_GLOB_SEQUENCE_TRUST_ONLYDIR
  974. directories == (m_flags & (directories | files)) || // 2
  975. #endif /* !UNIXSTL_GLOB_SEQUENCE_TRUST_ONLYDIR */
  976. files == (m_flags & (directories | files))) // 3
  977. {
  978. if(!m_buffer.resize(cItems))
  979. {
  980. #ifndef STLSOFT_CF_EXCEPTION_SUPPORT
  981. m_base = NULL;
  982. return 0;
  983. #endif /* !STLSOFT_CF_EXCEPTION_SUPPORT */
  984. }
  985. UNIXSTL_ASSERT(m_buffer.size() == cItems);
  986. base = static_cast<char_type**>(memcpy(&m_buffer[0], base, m_buffer.size() * sizeof(char_type*)));
  987. }
  988. // This section elides dots directories.
  989. if(elidingDots)
  990. {
  991. #ifndef UNIXSTL_GLOB_SEQUENCE_TRUST_NODOTSDIRS
  992. // Now remove the dots. If located at the start of
  993. // the gl buffer, then simply increment m_base to
  994. // be above that. If not then rearrange the base
  995. // two pointers such that they are there.
  996. us_bool_t bFoundDot1 = false;
  997. us_bool_t bFoundDot2 = false;
  998. char_type** begin = base;
  999. char_type** const end = begin + cItems;
  1000. for(; begin != end; ++begin)
  1001. {
  1002. us_bool_t bTwoDots = false;
  1003. if(is_dots_maybe_slashed_(*begin, &bTwoDots))
  1004. {
  1005. // Swap with whatever is at base[0]
  1006. if(begin != base)
  1007. {
  1008. stlsoft_ns_qual(std_swap)(*begin, *base);
  1009. }
  1010. ++base;
  1011. --cItems;
  1012. // We're only going to get one "." and one ".."
  1013. (bTwoDots ? bFoundDot2 : bFoundDot1) = true;
  1014. if( bFoundDot1 &&
  1015. bFoundDot2)
  1016. {
  1017. break;
  1018. }
  1019. }
  1020. }
  1021. #endif /* !UNIXSTL_GLOB_SEQUENCE_TRUST_NODOTSDIRS */
  1022. }
  1023. // This section performs the main filtering section, with
  1024. // conditional shortcuts for if any of the following hold:
  1025. //
  1026. // 1. Looking for files only
  1027. // - and GLOB_ONLYREG is supported
  1028. // 2. Looking for directories only
  1029. // - and GLOB_ONLYDIR is supported
  1030. // 3. Looking for anything
  1031. //
  1032. #ifdef UNIXSTL_GLOB_SEQUENCE_TRUST_ONLYREG
  1033. // 1. Looking for files only
  1034. if(files == (m_flags & (directories | files)))
  1035. {
  1036. ; // Nothing to do
  1037. }
  1038. else
  1039. #endif /* UNIXSTL_GLOB_SEQUENCE_TRUST_ONLYREG */
  1040. #ifdef UNIXSTL_GLOB_SEQUENCE_TRUST_ONLYDIR
  1041. // 2. Looking for directories only
  1042. if(directories == (m_flags & (directories | files)))
  1043. {
  1044. ; // Nothing to do
  1045. }
  1046. else
  1047. #endif /* UNIXSTL_GLOB_SEQUENCE_TRUST_ONLYDIR */
  1048. // 3. Looking for anything
  1049. if(0 == (m_flags & (directories | files)))
  1050. {
  1051. // NOTE: this conditional branch is a future-compatibility
  1052. // feature, for when sockets and links are supported
  1053. ; // Nothing to do
  1054. }
  1055. else
  1056. {
  1057. // Must filter based on type ascertained by call to stat()
  1058. // (except if we trust MARKDIR
  1059. char_type** begin = base;
  1060. char_type** const end = begin + cItems;
  1061. for(; begin != end; ++begin)
  1062. {
  1063. // Now need to process the file, by using stat
  1064. traits_type::stat_data_type st;
  1065. char_type const* const entry = *begin;
  1066. // Shortcut relying on mark, based on the assumption that
  1067. // a strlen()-equiv. operation is faster than a call to
  1068. // stat().
  1069. # ifndef UNIXSTL_GLOB_SEQUENCE_DONT_TRUST_MARK
  1070. if(markDirs == (m_flags & markDirs))
  1071. {
  1072. bool const isDirectory = traits_type::has_dir_end(entry);
  1073. if( isDirectory &&
  1074. directories == (m_flags & (directories)))
  1075. {
  1076. // It is a directory, and we want directories, so
  1077. // don't elide (by continue-ing)
  1078. continue;
  1079. }
  1080. else
  1081. if( !isDirectory &&
  1082. files == (m_flags & (directories | files)))
  1083. {
  1084. // It is not a directory, and we want files,
  1085. // so don't elide (by continue-ing)
  1086. continue;
  1087. }
  1088. }
  1089. else
  1090. # endif /* !UNIXSTL_GLOB_SEQUENCE_DONT_TRUST_MARK */
  1091. if(!traits_type::stat(entry, &st))
  1092. {
  1093. // We could throw an exception here, but it might just be
  1094. // the case that a file has been deleted subsequent to its
  1095. // having been included in the glob list. As such, it makes
  1096. // more sense to just kick it from the list
  1097. // TODO: Consider adding a callback function here, which can elect to throw, if the application requires that. Also, consider a throwOnStat flag
  1098. }
  1099. else
  1100. { // stat() succeeded
  1101. if( files == (m_flags & (files)) &&
  1102. traits_type::is_file(&st))
  1103. {
  1104. continue; // A file, so accept it
  1105. }
  1106. else
  1107. if( directories == (m_flags & (directories)) &&
  1108. traits_type::is_directory(&st))
  1109. {
  1110. continue; // A directory, so accept it
  1111. }
  1112. else
  1113. {
  1114. }
  1115. }
  1116. // This section elides the entry from the list
  1117. //
  1118. // Note that there is no test here to determine whether or not
  1119. // begin == base. It is assumed that most cases of file elision
  1120. // will involve several files - how many directories have just
  1121. // one file in them? - so the test would actually be a
  1122. // pessimisation
  1123. // Swap with whatever is at base[0]
  1124. stlsoft_ns_qual(std_swap)(*begin, *base);
  1125. ++base;
  1126. --cItems;
  1127. }
  1128. }
  1129. // Ensure we've not corrupted the sort order
  1130. if( 0 == (m_flags & noSort) &&
  1131. cItems != static_cast<us_size_t>(m_glob.gl_pathc))
  1132. {
  1133. unixstl_ns_qual_std(sort)(base, base + cItems);
  1134. }
  1135. // Set m_base and m_cItems to the correct values, with
  1136. // or without dots. m_base is cast here to remove the
  1137. // need for const-casting throughout the rest of the
  1138. // class
  1139. m_base = const_cast<char_type const**>(base);
  1140. // Everything has succeeded, so give ownership over to the
  1141. // glob_sequence instance
  1142. cleanup.detach();
  1143. return cItems;
  1144. }
  1145. }
  1146. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  1147. /* ////////////////////////////////////////////////////////////////////// */
  1148. #ifndef _UNIXSTL_NO_NAMESPACE
  1149. # if defined(_STLSOFT_NO_NAMESPACE) || \
  1150. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  1151. } // namespace unixstl
  1152. # else
  1153. } // namespace unixstl_project
  1154. } // namespace stlsoft
  1155. # endif /* _STLSOFT_NO_NAMESPACE */
  1156. #endif /* !_UNIXSTL_NO_NAMESPACE */
  1157. /* ////////////////////////////////////////////////////////////////////// */
  1158. #endif /* !UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_GLOB_SEQUENCE */
  1159. /* ///////////////////////////// end of file //////////////////////////// */