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.

530 lines
18 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: inetstl/filesystem/searchspec_sequence.hpp
  3. *
  4. * Purpose: Contains the searchspec_sequence template class, and ANSI
  5. * and Unicode specialisations thereof.
  6. *
  7. * Notes: 1. The original implementation of the class had the const_iterator
  8. * and value_type as nested classes. Unfortunately, Visual C++ 5 &
  9. * 6 both had either compilation or linking problems so these are
  10. * regretably now implemented as independent classes.
  11. *
  12. * 2. This class was described in detail in the article
  13. * "Adapting Windows Enumeration Models to STL Iterator Concepts"
  14. * (http://www.windevnet.com/documents/win0303a/), in the March
  15. * 2003 issue of Windows Developer Network (http://windevnet.com).
  16. *
  17. * Created: 1st May 2004
  18. * Updated: 10th August 2009
  19. *
  20. * Home: http://stlsoft.org/
  21. *
  22. * Copyright (c) 2004-2009, Matthew Wilson and Synesis Software
  23. * All rights reserved.
  24. *
  25. * Redistribution and use in source and binary forms, with or without
  26. * modification, are permitted provided that the following conditions are met:
  27. *
  28. * - Redistributions of source code must retain the above copyright notice, this
  29. * list of conditions and the following disclaimer.
  30. * - Redistributions in binary form must reproduce the above copyright notice,
  31. * this list of conditions and the following disclaimer in the documentation
  32. * and/or other materials provided with the distribution.
  33. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  34. * any contributors may be used to endorse or promote products derived from
  35. * this software without specific prior written permission.
  36. *
  37. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  38. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  39. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  40. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  41. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  42. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  43. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  44. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  45. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  46. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  47. * POSSIBILITY OF SUCH DAMAGE.
  48. *
  49. * ////////////////////////////////////////////////////////////////////// */
  50. /** \file inetstl/filesystem/searchspec_sequence.hpp
  51. *
  52. * \brief [C++ only] Definition of the inetstl::searchspec_sequence
  53. * class template
  54. * (\ref group__library__filesystem "File System" Library).
  55. */
  56. #ifndef INETSTL_INCL_INETSTL_FILESYSTEM_HPP_SEARCHSPEC_SEQUENCE
  57. #define INETSTL_INCL_INETSTL_FILESYSTEM_HPP_SEARCHSPEC_SEQUENCE
  58. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  59. # define STLSOFT_VER_INETSTL_FILESYSTEM_HPP_SEARCHSPEC_SEQUENCE_MAJOR 5
  60. # define STLSOFT_VER_INETSTL_FILESYSTEM_HPP_SEARCHSPEC_SEQUENCE_MINOR 1
  61. # define STLSOFT_VER_INETSTL_FILESYSTEM_HPP_SEARCHSPEC_SEQUENCE_REVISION 5
  62. # define STLSOFT_VER_INETSTL_FILESYSTEM_HPP_SEARCHSPEC_SEQUENCE_EDIT 55
  63. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  64. /* /////////////////////////////////////////////////////////////////////////
  65. * Includes
  66. */
  67. #ifndef INETSTL_INCL_INETSTL_H_INETSTL
  68. # include <inetstl/inetstl.h>
  69. #endif /* !INETSTL_INCL_INETSTL_H_INETSTL */
  70. #ifdef STLSOFT_CF_PRAGMA_MESSAGE_SUPPORT
  71. # pragma message("This file is now obsolete, and will be removed in a future release. The inetstl::basic_findfile_sequence class now supports multi-part patterns. This file will be removed from a future release.")
  72. #endif /* STLSOFT_CF_PRAGMA_MESSAGE_SUPPORT */
  73. #ifndef INETSTL_OS_IS_WINDOWS
  74. # error This file is currently compatible only with the Win32/Win64 API
  75. #endif /* !INETSTL_OS_IS_WINDOWS */
  76. #ifndef STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS
  77. # include <stlsoft/collections/util/collections.hpp>
  78. #endif /* !STLSOFT_INCL_STLSOFT_COLLECTIONS_UTIL_HPP_COLLECTIONS */
  79. #ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_SIMPLE_STRING
  80. # include <stlsoft/string/simple_string.hpp>
  81. #endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_SIMPLE_STRING */
  82. #ifndef STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_HPP_STRING
  83. # include <stlsoft/shims/access/string.hpp>
  84. #endif /* !STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_HPP_STRING */
  85. #ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_STRING_TOKENISER
  86. # include <stlsoft/string/string_tokeniser.hpp>
  87. #endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_STRING_TOKENISER */
  88. #ifndef STLSOFT_COMPILER_IS_WATCOM
  89. # ifndef STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER
  90. # include <stlsoft/util/std/iterator_helper.hpp>
  91. # endif /* !STLSOFT_INCL_STLSOFT_UTIL_STD_HPP_ITERATOR_HELPER */
  92. #endif /* compiler */
  93. /* /////////////////////////////////////////////////////////////////////////
  94. * Namespace
  95. */
  96. #ifndef _INETSTL_NO_NAMESPACE
  97. # if defined(_STLSOFT_NO_NAMESPACE) || \
  98. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  99. /* There is no stlsoft namespace, so must define ::inetstl */
  100. namespace inetstl
  101. {
  102. # else
  103. /* Define stlsoft::inetstl_project */
  104. namespace stlsoft
  105. {
  106. namespace inetstl_project
  107. {
  108. # endif /* _STLSOFT_NO_NAMESPACE */
  109. #endif /* !_INETSTL_NO_NAMESPACE */
  110. /* /////////////////////////////////////////////////////////////////////////
  111. * Functions
  112. */
  113. template <ss_typename_param_k T>
  114. inline void call_set_null(T *&pt, void (T::*F)())
  115. {
  116. INETSTL_ASSERT(NULL != pt);
  117. (pt->*F)();
  118. pt = NULL;
  119. }
  120. /* /////////////////////////////////////////////////////////////////////////
  121. * Classes
  122. */
  123. /** \brief Provides multi-pattern functionality over a file-system search sequence class
  124. *
  125. * \ingroup group__library__filesystem
  126. */
  127. template <ss_typename_param_k S>
  128. class searchspec_sequence
  129. : public stlsoft_ns_qual(stl_collection_tag)
  130. {
  131. public:
  132. /// The underlying find sequence type
  133. typedef S find_sequence_type;
  134. /// The current parameterisation of the type
  135. typedef searchspec_sequence<S> class_type;
  136. private:
  137. typedef searchspec_sequence<S> outer_class_type;
  138. typedef ss_typename_type_k find_sequence_type::traits_type traits_type;
  139. public:
  140. /// The character type
  141. typedef ss_typename_type_k find_sequence_type::char_type char_type;
  142. /// The value type
  143. typedef ss_typename_type_k find_sequence_type::value_type value_type;
  144. /// The size type
  145. typedef ss_typename_type_k find_sequence_type::size_type size_type;
  146. /// The non-mutable (const) reference type
  147. typedef ss_typename_type_k find_sequence_type::const_reference const_reference;
  148. /// The non-mutating (const) iterator type
  149. class const_iterator;
  150. private:
  151. typedef basic_simple_string<char_type> string_type;
  152. typedef string_tokeniser<string_type, char> tokeniser_type;
  153. public:
  154. /// Default constructor
  155. searchspec_sequence()
  156. : m_hconn(NULL)
  157. , m_rootDir(null_str_())
  158. , m_searchSpec(null_str_())
  159. , m_delimiter('\0')
  160. , m_flags(0)
  161. {}
  162. /// Creates a search sequence for the given connection, search specification and delimiter
  163. ///
  164. /// \note Assumes the current directory
  165. searchspec_sequence(HINTERNET hconn, char_type const* searchSpec, char_type delimiter)
  166. : m_hconn(hconn)
  167. , m_rootDir(dot1_str_())
  168. , m_searchSpec(searchSpec)
  169. , m_delimiter(delimiter)
  170. , m_flags(0)
  171. {}
  172. /// Creates a search sequence for the given connection, search specification, delimiter and flags
  173. ///
  174. /// \note Assumes the current directory
  175. searchspec_sequence(HINTERNET hconn, char_type const* searchSpec, char_type delimiter, ss_int_t flags)
  176. : m_hconn(hconn)
  177. , m_rootDir(dot1_str_())
  178. , m_searchSpec(searchSpec)
  179. , m_delimiter(delimiter)
  180. , m_flags(flags)
  181. {}
  182. /// Creates a search sequence for the given connection, root directory, search specification and delimiter
  183. searchspec_sequence(HINTERNET hconn, char_type const* rootDir, char_type const* searchSpec, char_type delimiter)
  184. : m_hconn(hconn)
  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 connection, root directory, search specification, delimiter and flags
  191. searchspec_sequence(HINTERNET hconn, char_type const* rootDir, char_type const* searchSpec, char_type delimiter, ss_int_t flags)
  192. : m_hconn(hconn)
  193. , m_rootDir(rootDir)
  194. , m_searchSpec(searchSpec)
  195. , m_delimiter(delimiter)
  196. , m_flags(flags)
  197. {}
  198. private:
  199. struct search_state
  200. {
  201. HINTERNET m_hconn;
  202. string_type m_rootDir;
  203. ss_int_t m_flags;
  204. tokeniser_type m_tokens;
  205. ss_typename_type_k tokeniser_type::const_iterator m_tokensNext;
  206. ss_typename_type_k tokeniser_type::const_iterator m_tokensEnd;
  207. find_sequence_type *m_entries;
  208. ss_typename_type_k find_sequence_type::const_iterator m_entriesNext;
  209. ss_typename_type_k find_sequence_type::const_iterator m_entriesEnd;
  210. ss_sint32_t m_cRefs;
  211. private:
  212. search_state(HINTERNET hconn, char_type const* rootDir, char_type const* searchSpec, char_type delimiter, ss_int_t flags)
  213. : m_hconn(hconn)
  214. , m_rootDir(rootDir)
  215. , m_flags(flags)
  216. , m_tokens(searchSpec, delimiter)
  217. , m_tokensNext(m_tokens.begin())
  218. , m_tokensEnd(m_tokens.end())
  219. , m_entries(new find_sequence_type(hconn, ::stlsoft::c_str_ptr(m_rootDir), ::stlsoft::c_str_ptr(*m_tokensNext), m_flags))
  220. , m_entriesNext(m_entries->begin())
  221. , m_entriesEnd(m_entries->end())
  222. , m_cRefs(1)
  223. {
  224. while(m_entriesNext == m_entriesEnd)
  225. {
  226. ++m_tokensNext;
  227. if(m_tokensNext == m_tokensEnd)
  228. {
  229. break;
  230. }
  231. else
  232. {
  233. INETSTL_ASSERT(NULL != m_entries);
  234. stlsoft_destroy_instance_fn(m_entries);
  235. m_entries = new(m_entries) find_sequence_type(m_hconn, ::stlsoft::c_str_ptr(m_rootDir), ::stlsoft::c_str_ptr(*m_tokensNext), m_flags);
  236. m_entriesEnd = m_entries->end();
  237. m_entriesNext = m_entries->begin();
  238. }
  239. }
  240. }
  241. #if defined(STLSOFT_COMPILER_IS_MSVC) && \
  242. _MSC_VER < 1300
  243. friend class const_iterator;
  244. #endif /* compiler */
  245. public:
  246. static search_state *create(HINTERNET hconn, char_type const* rootDir, char_type const* searchSpec, char_type delimiter, ss_int_t flags)
  247. {
  248. search_state *ss = new search_state(hconn, rootDir, searchSpec, delimiter, flags);
  249. if(ss->m_tokensNext == ss->m_tokensEnd)
  250. {
  251. delete ss;
  252. ss = NULL;
  253. }
  254. return ss;
  255. }
  256. public:
  257. bool next()
  258. {
  259. if(m_tokensNext == m_tokensEnd)
  260. {
  261. return false;
  262. }
  263. INETSTL_ASSERT(m_tokensNext != m_tokensEnd);
  264. INETSTL_ASSERT(NULL != m_entries || m_tokensNext == m_tokensEnd);
  265. // We are doing two enumerations here.
  266. //
  267. // The outer enumeration is over the tokens, the
  268. // inner is over the file entries.
  269. ++m_entriesNext;
  270. while(m_entriesNext == m_entriesEnd)
  271. {
  272. ++m_tokensNext;
  273. if(m_tokensNext == m_tokensEnd)
  274. {
  275. return false;
  276. }
  277. else
  278. {
  279. INETSTL_ASSERT(NULL != m_entries);
  280. stlsoft_destroy_instance_fn(m_entries);
  281. m_entries = new(m_entries) find_sequence_type(m_hconn, ::stlsoft::c_str_ptr(m_rootDir), ::stlsoft::c_str_ptr(*m_tokensNext), m_flags);
  282. m_entriesEnd = m_entries->end();
  283. m_entriesNext = m_entries->begin();
  284. }
  285. }
  286. return true;
  287. }
  288. void Release()
  289. {
  290. if(0 == --m_cRefs)
  291. {
  292. delete this;
  293. }
  294. }
  295. #if defined(STLSOFT_CF_COMPILER_WARNS_NO_PUBLIC_DTOR)
  296. protected:
  297. #else /* ? STLSOFT_CF_COMPILER_WARNS_NO_PUBLIC_DTOR */
  298. private:
  299. #endif /* STLSOFT_CF_COMPILER_WARNS_NO_PUBLIC_DTOR */
  300. ~search_state() stlsoft_throw_0()
  301. {
  302. delete m_entries;
  303. }
  304. };
  305. public:
  306. /// The const_iterator type for the searchspec_sequence
  307. class const_iterator
  308. {
  309. private:
  310. typedef const_iterator class_type;
  311. private:
  312. friend class searchspec_sequence<S>;
  313. const_iterator(HINTERNET hconn, char_type const* rootDir, char_type const* searchSpec, char_type delimiter, ss_int_t flags)
  314. : m_searchState(search_state::create(hconn, rootDir, searchSpec, delimiter, flags))
  315. {}
  316. public:
  317. /// Default constructor
  318. const_iterator()
  319. : m_searchState(NULL)
  320. {}
  321. /// Destructor
  322. ~const_iterator() stlsoft_throw_0()
  323. {
  324. if(NULL != m_searchState)
  325. {
  326. m_searchState->Release();
  327. }
  328. }
  329. /// Copy constructor
  330. const_iterator(class_type const& rhs)
  331. : m_searchState(rhs.m_searchState)
  332. {
  333. if(NULL != m_searchState)
  334. {
  335. ++m_searchState->m_cRefs;
  336. }
  337. }
  338. class_type& operator =(class_type const& rhs)
  339. {
  340. if(NULL != m_searchState)
  341. {
  342. m_searchState->Release();
  343. }
  344. m_searchState = rhs.m_searchState;
  345. if(NULL != m_searchState)
  346. {
  347. ++m_searchState->m_cRefs;
  348. }
  349. return *this;
  350. }
  351. public:
  352. class_type& operator ++()
  353. {
  354. INETSTL_ASSERT(NULL != m_searchState);
  355. if(!m_searchState->next())
  356. {
  357. #if defined(STLSOFT_COMPILER_IS_MSVC) && \
  358. _MSC_VER < 1300
  359. m_searchState->Release();
  360. m_searchState = NULL;
  361. #else /* ? compiler */
  362. call_set_null(m_searchState, &search_state::Release);
  363. #endif /* compiler */
  364. }
  365. return *this;
  366. }
  367. class_type operator ++(int)
  368. {
  369. class_type ret(*this);
  370. operator ++();
  371. return ret;
  372. }
  373. /// Dereference to return the value at the current position
  374. const value_type operator *() const
  375. {
  376. INETSTL_ASSERT(NULL != m_searchState);
  377. return *m_searchState->m_entriesNext;
  378. }
  379. ss_bool_t operator ==(class_type const& rhs) const
  380. {
  381. // Only evaluate the same when both are at their ends
  382. return (NULL == m_searchState) && (NULL == rhs.m_searchState);
  383. }
  384. ss_bool_t operator !=(class_type const& rhs) const
  385. {
  386. return !operator ==(rhs);
  387. }
  388. private:
  389. search_state *m_searchState;
  390. };
  391. public:
  392. /// Begins the iteration
  393. ///
  394. /// \return An iterator representing the start of the sequence
  395. const_iterator begin() const
  396. {
  397. return const_iterator(m_hconn, ::stlsoft::c_str_ptr(m_rootDir), ::stlsoft::c_str_ptr(m_searchSpec), m_delimiter, m_flags);
  398. }
  399. /// Ends the iteration
  400. ///
  401. /// \return An iterator representing the end of the sequence
  402. const_iterator end() const
  403. {
  404. return const_iterator();
  405. }
  406. public:
  407. /// \brief Indicates whether the sequence is empty
  408. ss_bool_t empty() const
  409. {
  410. return begin() == end();
  411. }
  412. // Implementation
  413. private:
  414. static char_type const* null_str_()
  415. {
  416. static char_type s_null[1] = { '\0' };
  417. return s_null;
  418. }
  419. static char_type const* dot1_str_()
  420. {
  421. static char_type s_dot1[2] = { '.', '\0' };
  422. return s_dot1;
  423. }
  424. private:
  425. HINTERNET m_hconn;
  426. string_type m_rootDir;
  427. string_type m_searchSpec;
  428. char_type m_delimiter;
  429. ss_int_t m_flags;
  430. };
  431. ////////////////////////////////////////////////////////////////////////////
  432. // Unit-testing
  433. #ifdef STLSOFT_UNITTEST
  434. # include "./unittest/searchspec_sequence_unittest_.h"
  435. #endif /* STLSOFT_UNITTEST */
  436. ////////////////////////////////////////////////////////////////////////////
  437. // Implementation
  438. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  439. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  440. /* ////////////////////////////////////////////////////////////////////// */
  441. #ifndef _INETSTL_NO_NAMESPACE
  442. # if defined(_STLSOFT_NO_NAMESPACE) || \
  443. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  444. } // namespace inetstl
  445. # else
  446. } // namespace inetstl_project
  447. } // namespace stlsoft
  448. # endif /* _STLSOFT_NO_NAMESPACE */
  449. #endif /* !_INETSTL_NO_NAMESPACE */
  450. /* ////////////////////////////////////////////////////////////////////// */
  451. #endif /* INETSTL_INCL_INETSTL_FILESYSTEM_HPP_SEARCHSPEC_SEQUENCE */
  452. /* ///////////////////////////// end of file //////////////////////////// */