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.

553 lines
18 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: stlsoft/filesystem/searchspec_sequence.hpp
  3. *
  4. * Purpose: Contains the searchspec_sequence template class, and ANSI
  5. * and Unicode specialisations thereof.
  6. *
  7. * Thanks to: Jon Papaioannou for spotting a character encoding error in
  8. * one of the typedefs
  9. *
  10. * Created: 1st May 2004
  11. * Updated: 10th August 2009
  12. *
  13. * Home: http://stlsoft.org/
  14. *
  15. * Copyright (c) 2004-2009, 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 stlsoft/filesystem/searchspec_sequence.hpp
  44. *
  45. * \brief [C++ only] Definition of the stlsoft::searchspec_sequence class
  46. * template
  47. * (\ref group__library__filesystem "File System" Library).
  48. */
  49. #ifndef STLSOFT_INCL_STLSOFT_FILESYSTEM_HPP_SEARCHSPEC_SEQUENCE
  50. #define STLSOFT_INCL_STLSOFT_FILESYSTEM_HPP_SEARCHSPEC_SEQUENCE
  51. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  52. # define STLSOFT_VER_STLSOFT_FILESYSTEM_HPP_SEARCHSPEC_SEQUENCE_MAJOR 4
  53. # define STLSOFT_VER_STLSOFT_FILESYSTEM_HPP_SEARCHSPEC_SEQUENCE_MINOR 1
  54. # define STLSOFT_VER_STLSOFT_FILESYSTEM_HPP_SEARCHSPEC_SEQUENCE_REVISION 6
  55. # define STLSOFT_VER_STLSOFT_FILESYSTEM_HPP_SEARCHSPEC_SEQUENCE_EDIT 59
  56. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  57. /* /////////////////////////////////////////////////////////////////////////
  58. * Compatibility
  59. */
  60. /*
  61. [Incompatibilies-start]
  62. STLSOFT_COMPILER_IS_MSVC: _MSC_VER<1200
  63. STLSOFT_COMPILER_IS_WATCOM:
  64. [Incompatibilies-end]
  65. */
  66. /* /////////////////////////////////////////////////////////////////////////
  67. * Includes
  68. */
  69. #ifndef STLSOFT_INCL_STLSOFT_H_STLSOFT
  70. # include <stlsoft/stlsoft.h>
  71. #endif /* !STLSOFT_INCL_STLSOFT_H_STLSOFT */
  72. #if defined(STLSOFT_COMPILER_IS_MSVC) && \
  73. _MSC_VER < 1200
  74. # error stlsoft/filesystem/searchspec_sequence.hpp is not compatible with Visual C++ 5.0 or earlier
  75. #endif /* compiler */
  76. #ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_SIMPLE_STRING
  77. # include <stlsoft/string/simple_string.hpp>
  78. #endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_SIMPLE_STRING */
  79. #ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_STRING_TOKENISER
  80. # include <stlsoft/string/string_tokeniser.hpp>
  81. #endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_STRING_TOKENISER */
  82. #ifndef STLSOFT_COMPILER_IS_WATCOM
  83. # ifndef STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER
  84. # include <stlsoft/util/std/iterator_helper.hpp>
  85. # endif /* !STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER */
  86. #endif /* compiler */
  87. #ifndef STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS
  88. # include <stlsoft/collections/util/collections.hpp>
  89. #endif /* !STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS */
  90. /* /////////////////////////////////////////////////////////////////////////
  91. * Pre-processor
  92. *
  93. * Definition of the
  94. */
  95. /* /////////////////////////////////////////////////////////////////////////
  96. * Namespace
  97. */
  98. #ifndef _STLSOFT_NO_NAMESPACE
  99. namespace stlsoft
  100. {
  101. #endif /* _STLSOFT_NO_NAMESPACE */
  102. /* /////////////////////////////////////////////////////////////////////////
  103. * Functions
  104. */
  105. template <ss_typename_param_k T>
  106. inline void call_set_null(T *&pt, void (T::*F)())
  107. {
  108. STLSOFT_ASSERT(NULL != pt);
  109. (pt->*F)();
  110. pt = NULL;
  111. }
  112. /* /////////////////////////////////////////////////////////////////////////
  113. * Classes
  114. */
  115. /** \brief Provides multi-pattern functionality over a file-system search sequence class
  116. *
  117. * \ingroup group__library__filesystem
  118. */
  119. template <ss_typename_param_k S>
  120. class searchspec_sequence
  121. : public stl_collection_tag
  122. {
  123. /// \name Member Types
  124. /// @{
  125. public:
  126. /// The underlying find sequence type
  127. typedef S find_sequence_type;
  128. /// The current parameterisation of the type
  129. typedef searchspec_sequence<S> class_type;
  130. private:
  131. typedef searchspec_sequence<S> outer_class_type;
  132. typedef ss_typename_type_k find_sequence_type::traits_type traits_type;
  133. public:
  134. /// The character type
  135. typedef ss_typename_type_k find_sequence_type::char_type char_type;
  136. /// The value type
  137. typedef ss_typename_type_k find_sequence_type::value_type value_type;
  138. /// The size type
  139. typedef ss_typename_type_k find_sequence_type::size_type size_type;
  140. /// The non-mutable (const) reference type
  141. typedef ss_typename_type_k find_sequence_type::const_reference const_reference;
  142. /// The non-mutating (const) iterator type
  143. class const_iterator;
  144. private:
  145. typedef basic_simple_string<char_type> string_type;
  146. // TODO: Have all filesystem_traits that have a fixed length derive from a tag type, so that we can parameterise
  147. // based on that. Then reinstate the string type discrimination based on the traits
  148. // typedef basic_static_string<char_type, traits_type::maxPathLength> string_type;
  149. typedef string_tokeniser<string_type, char_type> tokeniser_type;
  150. /// @}
  151. /// \name Construction
  152. /// @{
  153. public:
  154. /// Creates a search sequence for the given search specification and delimiter
  155. ///
  156. /// \param searchSpec The multi-filter search specification, e.g. "*.cpp", "*.d:makefile:*.java"
  157. /// \param delimiter The delimiter to use, e.g. ':'
  158. ///
  159. /// \note Assumes the current directory
  160. searchspec_sequence(char_type const* searchSpec, char_type delimiter)
  161. : m_rootDir(get_root_dir())
  162. , m_searchSpec(searchSpec)
  163. , m_delimiter(delimiter)
  164. , m_flags(0)
  165. {}
  166. /// Creates a search sequence for the given search specification, delimiter and flags
  167. ///
  168. /// \param searchSpec The multi-filter search specification, e.g. "*.cpp", "*.d:makefile:*.java"
  169. /// \param delimiter The delimiter to use, e.g. ':'
  170. /// \param flags Flags specific to the underlying sequence
  171. ///
  172. /// \note Assumes the current directory
  173. searchspec_sequence(char_type const* searchSpec, char_type delimiter, ss_int_t flags)
  174. : m_rootDir(get_root_dir())
  175. , m_searchSpec(searchSpec)
  176. , m_delimiter(delimiter)
  177. , m_flags(flags)
  178. {}
  179. /// Creates a search sequence for the given root directory, search specification and delimiter
  180. ///
  181. /// \param rootDir The root directory of the search
  182. /// \param searchSpec The multi-filter search specification, e.g. "*.cpp", "*.d:makefile:*.java"
  183. /// \param delimiter The delimiter to use, e.g. ':'
  184. searchspec_sequence(char_type const* rootDir, char_type const* searchSpec, char_type delimiter)
  185. : m_rootDir(rootDir)
  186. , m_searchSpec(searchSpec)
  187. , m_delimiter(delimiter)
  188. , m_flags(0)
  189. {}
  190. /// Creates a search sequence for the given root directory, search specification, delimiter and flags
  191. ///
  192. /// \param rootDir The root directory of the search
  193. /// \param searchSpec The multi-filter search specification, e.g. "*.cpp", "*.d:makefile:*.java"
  194. /// \param delimiter The delimiter to use, e.g. ':'
  195. /// \param flags Flags specific to the underlying sequence
  196. searchspec_sequence(char_type const* rootDir, char_type const* searchSpec, char_type delimiter, ss_int_t flags)
  197. : m_rootDir(rootDir)
  198. , m_searchSpec(searchSpec)
  199. , m_delimiter(delimiter)
  200. , m_flags(flags)
  201. {}
  202. /// @}
  203. /// \name Implementation
  204. /// @{
  205. private:
  206. struct search_state
  207. {
  208. string_type m_rootDir;
  209. ss_int_t m_flags;
  210. tokeniser_type m_tokens;
  211. ss_typename_type_k tokeniser_type::const_iterator m_tokensNext;
  212. ss_typename_type_k tokeniser_type::const_iterator m_tokensEnd;
  213. find_sequence_type *m_entries;
  214. ss_typename_type_k find_sequence_type::const_iterator m_entriesNext;
  215. ss_typename_type_k find_sequence_type::const_iterator m_entriesEnd;
  216. ss_sint32_t m_cRefs;
  217. private:
  218. search_state(char_type const* rootDir, char_type const* searchSpec, char_type delimiter, ss_int_t flags)
  219. : m_rootDir(rootDir)
  220. , m_flags(flags)
  221. , m_tokens(searchSpec, delimiter)
  222. , m_tokensNext(m_tokens.begin())
  223. , m_tokensEnd(m_tokens.end())
  224. #if defined(STLSOFT_COMPILER_IS_VECTORC)
  225. , m_entries(new find_sequence_type(m_rootDir.c_str(), (*m_tokensNext).c_str(), m_flags))
  226. #else /* ? compiler */
  227. , m_entries(new find_sequence_type(c_str_ptr(m_rootDir), c_str_ptr(*m_tokensNext), m_flags))
  228. #endif /* compiler */
  229. , m_entriesNext(m_entries->begin())
  230. , m_entriesEnd(m_entries->end())
  231. , m_cRefs(1)
  232. {
  233. while(m_entriesNext == m_entriesEnd)
  234. {
  235. ++m_tokensNext;
  236. if(m_tokensNext == m_tokensEnd)
  237. {
  238. break;
  239. }
  240. else
  241. {
  242. STLSOFT_ASSERT(NULL != m_entries);
  243. stlsoft_destroy_instance_fn(m_entries);
  244. #if defined(STLSOFT_COMPILER_IS_VECTORC)
  245. m_entries = new(m_entries) find_sequence_type(m_rootDir.c_str(), (*m_tokensNext).c_str(), m_flags);
  246. #else /* ? compiler */
  247. m_entries = new(m_entries) find_sequence_type(c_str_ptr(m_rootDir), c_str_ptr(*m_tokensNext), m_flags);
  248. #endif /* compiler */
  249. m_entriesEnd = m_entries->end();
  250. m_entriesNext = m_entries->begin();
  251. }
  252. }
  253. }
  254. #if defined(STLSOFT_COMPILER_IS_MSVC) && \
  255. _MSC_VER < 1300
  256. friend class const_iterator;
  257. #endif /* compiler */
  258. public:
  259. static search_state *create(char_type const* rootDir, char_type const* searchSpec, char_type delimiter, ss_int_t flags)
  260. {
  261. search_state *ss = new search_state(rootDir, searchSpec, delimiter, flags);
  262. if(ss->m_tokensNext == ss->m_tokensEnd)
  263. {
  264. delete ss;
  265. ss = NULL;
  266. }
  267. return ss;
  268. }
  269. public:
  270. bool next()
  271. {
  272. if(m_tokensNext == m_tokensEnd)
  273. {
  274. return false;
  275. }
  276. STLSOFT_ASSERT(m_tokensNext != m_tokensEnd);
  277. STLSOFT_ASSERT(NULL != m_entries || m_tokensNext == m_tokensEnd);
  278. // We are doing two enumerations here.
  279. //
  280. // The outer enumeration is over the tokens, the
  281. // inner is over the file entries.
  282. ++m_entriesNext;
  283. while(m_entriesNext == m_entriesEnd)
  284. {
  285. ++m_tokensNext;
  286. if(m_tokensNext == m_tokensEnd)
  287. {
  288. return false;
  289. }
  290. else
  291. {
  292. STLSOFT_ASSERT(NULL != m_entries);
  293. stlsoft_destroy_instance_fn(m_entries);
  294. #if defined(STLSOFT_COMPILER_IS_VECTORC)
  295. m_entries = new(m_entries) find_sequence_type(m_rootDir.c_str(), (*m_tokensNext).c_str(), m_flags);
  296. #else /* ? compiler */
  297. m_entries = new(m_entries) find_sequence_type(c_str_ptr(m_rootDir), c_str_ptr(*m_tokensNext), m_flags);
  298. #endif /* compiler */
  299. m_entriesEnd = m_entries->end();
  300. m_entriesNext = m_entries->begin();
  301. }
  302. }
  303. return true;
  304. }
  305. void Release()
  306. {
  307. if(0 == --m_cRefs)
  308. {
  309. delete this;
  310. }
  311. }
  312. #if defined(STLSOFT_CF_COMPILER_WARNS_NO_PUBLIC_DTOR)
  313. protected:
  314. #else /* ? STLSOFT_CF_COMPILER_WARNS_NO_PUBLIC_DTOR */
  315. private:
  316. #endif /* STLSOFT_CF_COMPILER_WARNS_NO_PUBLIC_DTOR */
  317. ~search_state() stlsoft_throw_0()
  318. {
  319. delete m_entries;
  320. }
  321. };
  322. /// @}
  323. /// \name Iteration
  324. /// @{
  325. public:
  326. /// The const_iterator type for the searchspec_sequence
  327. class const_iterator
  328. {
  329. private:
  330. typedef const_iterator class_type;
  331. private:
  332. friend class searchspec_sequence<S>;
  333. const_iterator(char_type const* rootDir, char_type const* searchSpec, char_type delimiter, ss_int_t flags)
  334. : m_searchState(search_state::create(rootDir, searchSpec, delimiter, flags))
  335. {}
  336. public:
  337. /// Default constructor
  338. const_iterator()
  339. : m_searchState(NULL)
  340. {}
  341. /// Destructor
  342. ~const_iterator() stlsoft_throw_0()
  343. {
  344. if(NULL != m_searchState)
  345. {
  346. m_searchState->Release();
  347. }
  348. }
  349. /// Copy constructor
  350. const_iterator(class_type const& rhs)
  351. : m_searchState(rhs.m_searchState)
  352. {
  353. if(NULL != m_searchState)
  354. {
  355. ++m_searchState->m_cRefs;
  356. }
  357. }
  358. class_type& operator =(class_type const& rhs)
  359. {
  360. if(NULL != m_searchState)
  361. {
  362. m_searchState->Release();
  363. }
  364. m_searchState = rhs.m_searchState;
  365. if(NULL != m_searchState)
  366. {
  367. ++m_searchState->m_cRefs;
  368. }
  369. return *this;
  370. }
  371. public:
  372. class_type& operator ++()
  373. {
  374. STLSOFT_ASSERT(NULL != m_searchState);
  375. if(!m_searchState->next())
  376. {
  377. #if defined(STLSOFT_COMPILER_IS_MSVC) && \
  378. _MSC_VER < 1300
  379. m_searchState->Release();
  380. m_searchState = NULL;
  381. #else /* ? compiler */
  382. call_set_null(m_searchState, &search_state::Release);
  383. #endif /* compiler */
  384. }
  385. return *this;
  386. }
  387. class_type operator ++(int)
  388. {
  389. class_type ret(*this);
  390. operator ++();
  391. return ret;
  392. }
  393. /// Dereference to return the value at the current position
  394. const value_type operator *() const
  395. {
  396. STLSOFT_ASSERT(NULL != m_searchState);
  397. return *m_searchState->m_entriesNext;
  398. }
  399. ss_bool_t operator ==(class_type const& rhs) const
  400. {
  401. // Only evaluate the same when both are at their ends
  402. return (NULL == m_searchState) && (NULL == rhs.m_searchState);
  403. }
  404. ss_bool_t operator !=(class_type const& rhs) const
  405. {
  406. return !operator ==(rhs);
  407. }
  408. private:
  409. search_state *m_searchState;
  410. };
  411. /// @}
  412. /// \name Iteration
  413. /// @{
  414. public:
  415. /// Begins the iteration
  416. ///
  417. /// \return An iterator representing the start of the sequence
  418. const_iterator begin() const
  419. {
  420. #if defined(STLSOFT_COMPILER_IS_VECTORC)
  421. return const_iterator(m_rootDir.c_str(), (m_searchSpec).c_str(), m_delimiter, m_flags);
  422. #else /* ? compiler */
  423. return const_iterator(c_str_ptr(m_rootDir), c_str_ptr(m_searchSpec), m_delimiter, m_flags);
  424. #endif /* compiler */
  425. }
  426. /// Ends the iteration
  427. ///
  428. /// \return An iterator representing the end of the sequence
  429. const_iterator end() const
  430. {
  431. return const_iterator();
  432. }
  433. /// @}
  434. /// \name Attributes
  435. /// @{
  436. public:
  437. /// \brief Indicates whether the sequence is empty
  438. ss_bool_t empty() const
  439. {
  440. return begin() == end();
  441. }
  442. /// @}
  443. /// \name Implementation
  444. /// @{
  445. private:
  446. static char_type const* get_root_dir()
  447. {
  448. static char_type s_rootDir[2] = { '.', '\0' };
  449. return s_rootDir;
  450. }
  451. /// @}
  452. /// \name Members
  453. /// @{
  454. private:
  455. string_type m_rootDir;
  456. string_type m_searchSpec;
  457. char_type m_delimiter;
  458. ss_int_t m_flags;
  459. /// @}
  460. };
  461. ////////////////////////////////////////////////////////////////////////////
  462. // Unit-testing
  463. #ifdef STLSOFT_UNITTEST
  464. # include "./unittest/searchspec_sequence_unittest_.h"
  465. #endif /* STLSOFT_UNITTEST */
  466. ////////////////////////////////////////////////////////////////////////////
  467. // Implementation
  468. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  469. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  470. /* ////////////////////////////////////////////////////////////////////// */
  471. #ifndef _STLSOFT_NO_NAMESPACE
  472. } // namespace stlsoft
  473. #endif /* _STLSOFT_NO_NAMESPACE */
  474. /* ////////////////////////////////////////////////////////////////////// */
  475. #endif /* !STLSOFT_INCL_STLSOFT_FILESYSTEM_HPP_SEARCHSPEC_SEQUENCE */
  476. /* ///////////////////////////// end of file //////////////////////////// */