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.

2013 lines
60 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: winstl/filesystem/path.hpp
  3. *
  4. * Purpose: Simple class that represents a path.
  5. *
  6. * Created: 1st May 1993
  7. * Updated: 29th November 2010
  8. *
  9. * Thanks to: Pablo Aguilar for reporting defect in push_ext() (which
  10. * doesn't work for wide-string builds).
  11. *
  12. * Home: http://stlsoft.org/
  13. *
  14. * Copyright (c) 1993-2010, Matthew Wilson and Synesis Software
  15. * All rights reserved.
  16. *
  17. * Redistribution and use in source and binary forms, with or without
  18. * modification, are permitted provided that the following conditions are met:
  19. *
  20. * - Redistributions of source code must retain the above copyright notice, this
  21. * list of conditions and the following disclaimer.
  22. * - Redistributions in binary form must reproduce the above copyright notice,
  23. * this list of conditions and the following disclaimer in the documentation
  24. * and/or other materials provided with the distribution.
  25. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of
  26. * any contributors may be used to endorse or promote products derived from
  27. * this software without specific prior written permission.
  28. *
  29. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  30. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  31. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  32. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  33. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  34. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  35. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  36. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  37. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  38. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  39. * POSSIBILITY OF SUCH DAMAGE.
  40. *
  41. * ////////////////////////////////////////////////////////////////////// */
  42. /** \file winstl/filesystem/path.hpp
  43. *
  44. * \brief [C++ only] Definition of the winstl::basic_path class template
  45. * (\ref group__library__filesystem "File System" Library).
  46. */
  47. #ifndef WINSTL_INCL_WINSTL_FILESYSTEM_HPP_PATH
  48. #define WINSTL_INCL_WINSTL_FILESYSTEM_HPP_PATH
  49. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  50. # define WINSTL_VER_WINSTL_FILESYSTEM_HPP_PATH_MAJOR 6
  51. # define WINSTL_VER_WINSTL_FILESYSTEM_HPP_PATH_MINOR 6
  52. # define WINSTL_VER_WINSTL_FILESYSTEM_HPP_PATH_REVISION 20
  53. # define WINSTL_VER_WINSTL_FILESYSTEM_HPP_PATH_EDIT 261
  54. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  55. /* /////////////////////////////////////////////////////////////////////////
  56. * Includes
  57. */
  58. #ifndef WINSTL_INCL_WINSTL_H_WINSTL
  59. # include <winstl/winstl.h>
  60. #endif /* !WINSTL_INCL_WINSTL_H_WINSTL */
  61. #ifndef WINSTL_INCL_WINSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS
  62. # include <winstl/filesystem/filesystem_traits.hpp>
  63. #endif /* !WINSTL_INCL_WINSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS */
  64. #ifndef WINSTL_INCL_WINSTL_FILESYSTEM_HPP_FILE_PATH_BUFFER
  65. # include <winstl/filesystem/file_path_buffer.hpp>
  66. #endif /* !WINSTL_INCL_WINSTL_FILESYSTEM_HPP_FILE_PATH_BUFFER */
  67. #ifndef WINSTL_INCL_WINSTL_MEMORY_HPP_PROCESSHEAP_ALLOCATOR
  68. # include <winstl/memory/processheap_allocator.hpp>
  69. #endif /* !WINSTL_INCL_WINSTL_MEMORY_HPP_PROCESSHEAP_ALLOCATOR */
  70. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  71. # ifndef WINSTL_INCL_WINSTL_ERROR_HPP_WINDOWS_EXCEPTIONS
  72. # include <winstl/error/exceptions.hpp>
  73. # endif /* !WINSTL_INCL_WINSTL_ERROR_HPP_WINDOWS_EXCEPTIONS */
  74. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  75. #ifndef STLSOFT_INCL_STLSOFT_MEMORY_HPP_ALLOCATOR_FEATURES
  76. # include <stlsoft/memory/allocator_features.hpp> // for STLSOFT_LF_ALLOCATOR_REBIND_SUPPORT
  77. #endif /* !STLSOFT_INCL_STLSOFT_MEMORY_HPP_ALLOCATOR_FEATURES */
  78. #ifndef STLSOFT_INCL_STLSOFT_HPP_MEMORY_AUTO_BUFFER
  79. # include <stlsoft/memory/auto_buffer.hpp>
  80. #endif /* !STLSOFT_INCL_STLSOFT_HPP_MEMORY_AUTO_BUFFER */
  81. #ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_COPY_FUNCTIONS
  82. # include <stlsoft/string/copy_functions.hpp>
  83. #endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_COPY_FUNCTIONS */
  84. #ifndef STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_HPP_STRING
  85. # include <stlsoft/shims/access/string.hpp>
  86. #endif /* !STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_HPP_STRING */
  87. #ifndef STLSOFT_INCL_STLSOFT_UTIL_HPP_STD_SWAP
  88. # include <stlsoft/util/std_swap.hpp>
  89. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_HPP_STD_SWAP */
  90. #ifndef STLSOFT_INCL_STDEXCEPT
  91. # define STLSOFT_INCL_STDEXCEPT
  92. # include <stdexcept> // for std::logic_error
  93. #endif /* !STLSOFT_INCL_STDEXCEPT */
  94. /* /////////////////////////////////////////////////////////////////////////
  95. * Namespace
  96. */
  97. #ifndef _WINSTL_NO_NAMESPACE
  98. # if defined(_STLSOFT_NO_NAMESPACE) || \
  99. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  100. /* There is no stlsoft namespace, so must define ::winstl */
  101. namespace winstl
  102. {
  103. # else
  104. /* Define stlsoft::winstl_project */
  105. namespace stlsoft
  106. {
  107. namespace winstl_project
  108. {
  109. # endif /* _STLSOFT_NO_NAMESPACE */
  110. #endif /* !_WINSTL_NO_NAMESPACE */
  111. /* /////////////////////////////////////////////////////////////////////////
  112. * basic_path
  113. *
  114. * This class represents a path, and effectively acts as a C-string of its value.
  115. */
  116. /** Class used for composing and decomposing file-system paths.
  117. *
  118. * \ingroup group__library__filesystem
  119. *
  120. * \param C The character type
  121. * \param T The traits type. On translators that support default template arguments, this defaults to filesystem_traits<C>
  122. * \param A The allocator type. On translators that support default template arguments, this defaults to processheap_allocator<C>
  123. *
  124. * \note This class derives from the Synesis Software class Path, but has been influenced
  125. * by other, later, ideas. The idea of using the / operator for path concatenation was
  126. * sparked by the Boost implementation (although the details were not investigated prior
  127. * to this implementation, so the two may have significant semantic differences). This
  128. * has been added without requiring any major fundamental changes to the original
  129. * <code>push/pop</code>-based interface
  130. */
  131. template< ss_typename_param_k C
  132. #ifdef STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT
  133. , ss_typename_param_k T = filesystem_traits<C>
  134. , ss_typename_param_k A = processheap_allocator<C>
  135. #else /* ? STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT */
  136. , ss_typename_param_k T /* = filesystem_traits<C> */
  137. , ss_typename_param_k A /* = processheap_allocator<C> */
  138. #endif /* STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT */
  139. >
  140. class basic_path
  141. {
  142. /// \name Types
  143. /// @{
  144. public:
  145. /// The char type
  146. typedef C char_type;
  147. /// The traits type
  148. typedef T traits_type;
  149. /// The allocator type
  150. typedef A allocator_type;
  151. /// The current parameterisation of the type
  152. typedef basic_path<C, T, A> class_type;
  153. /// The size type
  154. typedef ws_size_t size_type;
  155. /// The Boolean type
  156. typedef ws_bool_t bool_type;
  157. // TODO: Use the slice string, and provide iterators over the directory parts
  158. /// @}
  159. /// \name Construction
  160. /// @{
  161. public:
  162. /// Constructs an empty path.
  163. ///
  164. /// \code
  165. /// winstl::path p;
  166. ///
  167. /// assert(0 == p.size());
  168. /// assert("" == p);
  169. /// \endcode
  170. basic_path();
  171. /// Constructs a path from a nul-terminated character string.
  172. ///
  173. /// \code
  174. /// winstl::path p("C:\\Windows");
  175. ///
  176. /// assert(10 == p.size());
  177. /// assert("C:\\Windows" == p);
  178. /// assert("C:\\WINDOWS" == p);
  179. /// assert("c:\\windows" == p);
  180. /// \endcode
  181. ///
  182. /// \pre len(path) <= size()
  183. ss_explicit_k basic_path(char_type const* path);
  184. #ifdef STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT
  185. /// Constructs a path from a string object.
  186. ///
  187. /// \remarks The string object may be any type for which the
  188. /// <b>c_str_len</b> and <b>c_str_data</b>
  189. /// \ref group__concept__shim__string_access "String Access Shims" are
  190. /// defined. The following example shows the use of a window handle
  191. /// (HWND). Other types supported are <code>std::exception</code>,
  192. /// <code>std::string</code>, <code>stlsoft::simple_string</code>,
  193. /// <code>winstl::error_desc</code>, and many more
  194. ///
  195. /// \code
  196. /// HWND hwndParent = . . .
  197. /// HWND hwnd = winstl::CreateEdit(hwndParent, "C:\\Windows", ES_LEFT, 0, 0, 10, 10, 1001);
  198. /// winstl::path p(hwnd);
  199. ///
  200. /// assert(10 == p.size());
  201. /// assert("C:\\Windows" == p);
  202. /// assert("C:\\WINDOWS" == p);
  203. /// assert("c:\\windows" == p);
  204. /// \endcode
  205. template<ss_typename_param_k S>
  206. ss_explicit_k basic_path(S const& s)
  207. {
  208. m_len = stlsoft_ns_qual(c_str_len)(s);
  209. traits_type::char_copy(&m_buffer[0], stlsoft_ns_qual(c_str_data)(s), m_len);
  210. m_buffer[m_len] = '\0';
  211. }
  212. #endif /* STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT */
  213. /// Constructs a path from a slice of a character string.
  214. ///
  215. /// \endcode
  216. /// winstl::path p("C:\\Windows\\system32", 10);
  217. ///
  218. /// assert(10 == p.size());
  219. /// assert("C:\\Windows" == p);
  220. /// assert("C:\\WINDOWS" == p);
  221. /// assert("c:\\windows" == p);
  222. /// \endcode
  223. basic_path(char_type const* path, size_type cch);
  224. #ifndef STLSOFT_CF_NO_COPY_CTOR_AND_COPY_CTOR_TEMPLATE_OVERLOAD
  225. /// Copies the contents of \c rhs
  226. basic_path(class_type const& rhs);
  227. #endif /* !STLSOFT_CF_NO_COPY_CTOR_AND_COPY_CTOR_TEMPLATE_OVERLOAD */
  228. #ifndef STLSOFT_CF_NO_COPY_CTOR_AND_COPY_CTOR_TEMPLATE_OVERLOAD
  229. /// Copies the contents of \c rhs
  230. class_type& operator =(class_type const& rhs);
  231. #endif /* !STLSOFT_CF_NO_COPY_CTOR_AND_COPY_CTOR_TEMPLATE_OVERLOAD */
  232. /// Copies the contents of \c rhs
  233. class_type& operator =(char_type const* rhs);
  234. #ifdef STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT
  235. /// Copies the contents of \c s
  236. template<ss_typename_param_k S>
  237. class_type& operator =(S const& s)
  238. {
  239. return operator_equal_(stlsoft_ns_qual(c_str_ptr)(s));
  240. }
  241. #endif /* STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT */
  242. // Creates a root path
  243. static class_type root(char_type const* s);
  244. #ifdef STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT
  245. // Creates a root path
  246. template<ss_typename_param_k S>
  247. static class_type root(S const& s)
  248. {
  249. return root(stlsoft_ns_qual(c_str_ptr)(s));
  250. }
  251. #endif /* STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT */
  252. /// @}
  253. /// \name Operations
  254. /// @{
  255. public:
  256. /// Appends the contents of \c rhs to the path
  257. class_type& push(class_type const& rhs, bool_type bAddPathNameSeparator = false);
  258. /// Appends the contents of \c rhs to the path
  259. class_type& push(char_type const* rhs, bool_type bAddPathNameSeparator = false);
  260. /// Appends the contents of \c rhs to the path as an extension
  261. class_type& push_ext(class_type const& rhs, bool_type bAddPathNameSeparator = false);
  262. /// Appends the contents of \c rhs to the path as an extension
  263. class_type& push_ext(char_type const* rhs, bool_type bAddPathNameSeparator = false);
  264. /// Ensures that the path has a trailing path name separator
  265. ///
  266. /// \remarks If the path currently contains path name separators, and
  267. /// they are all forward slashes '/', then a forward slash will be
  268. /// used; otherwise a backslash '\\' will be used.
  269. class_type& push_sep();
  270. /// Pops the last path element from the path
  271. ///
  272. /// \note In previous versions, this operation did not remove the
  273. /// left-most path component. That behaviour is no longer supported,
  274. /// and the method will now leave the path instance empty in that
  275. /// case.
  276. class_type& pop(bool_type bRemoveTrailingPathNameSeparator = true);
  277. /// Ensures that the path does not have a trailing path name separator
  278. ///
  279. /// \note Does not trim the separator character from the root designator
  280. ///
  281. /// \note This method is idempotent.
  282. class_type& pop_sep() stlsoft_throw_0();
  283. /// Removes the extension, if any, from the file component of the path
  284. ///
  285. /// \note This method is idempotent.
  286. class_type& pop_ext() stlsoft_throw_0();
  287. /// Equivalent to push()
  288. class_type& operator /=(char_type const* rhs);
  289. #if !defined(STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT) || \
  290. defined(STLSOFT_CF_MEMBER_TEMPLATE_OVERLOAD_DISCRIMINATED)
  291. /// Equivalent to push()
  292. class_type& operator /=(class_type const& rhs);
  293. #endif /* !STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT || STLSOFT_CF_MEMBER_TEMPLATE_OVERLOAD_DISCRIMINATED */
  294. #if defined(STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT)
  295. /// Equivalent to push()
  296. template <ss_typename_param_k S>
  297. class_type& operator /=(S const& rhs)
  298. {
  299. return push(stlsoft_ns_qual(c_str_ptr)(rhs));
  300. }
  301. #endif /* STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT */
  302. /// Removes all content
  303. void clear();
  304. /// Converts the path to absolute form
  305. class_type& make_absolute(bool_type bRemoveTrailingPathNameSeparator = true);
  306. /// Canonicalises the path
  307. ///
  308. /// Canonicalises the path, removing all "./" parts and evaluating all
  309. /// "../" parts. Any path with only one part will not be canonicalised.
  310. /// A leading '.' will be preserved if no other '..' or "normal" parts
  311. /// are contained.
  312. ///
  313. /// \param bRemoveTrailingPathNameSeparator Removes any trailing
  314. /// separator, even if no other changes have been made.
  315. class_type& canonicalise(bool_type bRemoveTrailingPathNameSeparator = true);
  316. /// @}
  317. /// \name Attributes
  318. /// @{
  319. public:
  320. /// Returns a pointer to the part of the path after the last path name separator
  321. ///
  322. /// \note If the path represents a directory, the name of the directory will be returned, except
  323. /// if the path is terminated by the path name separator
  324. ///
  325. /// \note If the path contains no path name separator, the full path will be returned
  326. char_type const* get_file() const;
  327. /// Returns a pointer to the extension, or to the empty string if there is no extension
  328. char_type const* get_ext() const;
  329. /// Returns the length of the converted path
  330. size_type length() const;
  331. /// Returns the length of the converted path
  332. ///
  333. /// \remarks Equivalent to length()
  334. size_type size() const;
  335. /// The maximum possible length of a path
  336. static size_type max_size();
  337. /// Determines whether the path is empty
  338. bool_type empty() const;
  339. /// Conversion to a non-mutable (const) pointer to the path
  340. char_type const* c_str() const;
  341. /// Returns a non-mutable (const) reference to the character at
  342. /// the given index
  343. ///
  344. /// \note The behaviour is undefined if <code>index >= size()</code>.
  345. char_type const& operator [](size_type index) const;
  346. /// Indicates whether the path represents an existing file system entry
  347. bool_type exists() const;
  348. /// Indicates whether the path is rooted
  349. bool_type is_rooted() const;
  350. /// Indicates whether the path is absolute
  351. bool_type is_absolute() const;
  352. /// Indicates whether the path has a trailing separator
  353. bool_type has_sep() const;
  354. /// Copies the contents into a caller supplied buffer
  355. ///
  356. /// \param buffer Pointer to character buffer to receive the contents.
  357. /// May be NULL, in which case the method returns size().
  358. /// \param cchBuffer Number of characters of available space in \c buffer.
  359. size_type copy(char_type *buffer, size_type cchBuffer) const;
  360. /// @}
  361. /// \name Comparison
  362. /// @{
  363. public:
  364. /// Determines whether the instance holds a string that refers to
  365. /// the same file-system entity as the given string.
  366. ///
  367. /// \htmlonly
  368. /// <pre>
  369. /// winstl::path p("C:\\Windows\\system32\\..");
  370. ///
  371. /// assert(p != "C:\\WINDOWS\\");
  372. /// assert(!p.equal("C:\\WINDOWS\\"));
  373. /// assert(p.equivalent("C:\\WINDOWS\\"));
  374. /// </pre>
  375. /// \endhtmlonly
  376. bool_type equivalent(char_type const* rhs) const;
  377. /// Evaluates whether the two instances hold strings that refer
  378. /// to the same file-system entity.
  379. ///
  380. /// \remarks See \link winstl::basic_path::equivalent(C const* ) equivalent()\endlink for an example.
  381. ///
  382. /// \note The string comparison is case-insensitive.
  383. bool_type equivalent(class_type const& rhs) const;
  384. /// Evaluates whether the instance holds an identical string.
  385. ///
  386. /// \note The string comparison is case-insensitive.
  387. bool_type equal(char_type const* rhs) const;
  388. /// Evaluates whether the two instances hold identical strings.
  389. ///
  390. /// \note The string comparison is case-insensitive.
  391. bool_type equal(class_type const& rhs) const;
  392. /// @}
  393. /// \name Iteration
  394. /// @{
  395. public:
  396. #if 0
  397. directory_iterator dir_begin() const;
  398. directory_iterator dir_end() const;
  399. #endif /* 0 */
  400. /// @}
  401. // Implementation
  402. private:
  403. class_type& operator_equal_(char_type const* path);
  404. class_type& push_(char_type const* rhs, size_type cch, bool_type bAddPathNameSeparator);
  405. class_type& push_sep_(char_type sep);
  406. void swap(class_type& rhs);
  407. class_type& concat_(char_type const* rhs, size_type cch);
  408. bool_type has_dir_end_() const;
  409. static char_type const* last_slash_(char_type const* buffer, size_type len);
  410. static char_type const* next_slash_or_end(char_type const* p);
  411. static char_type const* next_part_or_end(char_type const* p);
  412. static char_type path_name_separator();
  413. static char_type path_name_separator_alt();
  414. // Member Types
  415. private:
  416. typedef basic_file_path_buffer< char_type
  417. , allocator_type
  418. > buffer_type_;
  419. struct part_type
  420. {
  421. enum Type
  422. {
  423. normal
  424. , dot
  425. , dotdot
  426. };
  427. size_type len;
  428. char_type const* p;
  429. Type type;
  430. };
  431. #ifdef STLSOFT_LF_ALLOCATOR_REBIND_SUPPORT
  432. typedef ss_typename_type_k A::ss_template_qual_k rebind<part_type>::other part_ator_type_;
  433. #else /* ? STLSOFT_LF_ALLOCATOR_REBIND_SUPPORT */
  434. # ifdef WIN32
  435. typedef ss_typename_type_k processheap_allocator<part_type> part_ator_type_;
  436. # else /* ? OS */
  437. typedef ss_typename_type_k allocator_selector<part_type>::allocator_type part_ator_type_;
  438. # endif /* OS */
  439. #endif /* STLSOFT_LF_ALLOCATOR_REBIND_SUPPORT */
  440. typedef stlsoft_ns_qual(auto_buffer_old)< part_type
  441. , part_ator_type_
  442. # ifdef WIN32
  443. , WINSTL_CONST_MAX_PATH / 2
  444. # endif /* OS */
  445. > part_buffer_type_;
  446. static size_type coalesce_parts_(part_buffer_type_& parts);
  447. // Member Variables
  448. private:
  449. buffer_type_ m_buffer;
  450. size_type m_len;
  451. };
  452. /* /////////////////////////////////////////////////////////////////////////
  453. * Typedefs for commonly encountered types
  454. */
  455. /** Specialisation of the basic_path template for the ANSI character type \c char
  456. *
  457. * \ingroup group__library__filesystem
  458. */
  459. typedef basic_path<ws_char_a_t, filesystem_traits<ws_char_a_t> > path_a;
  460. /** Specialisation of the basic_path template for the Unicode character type \c wchar_t
  461. *
  462. * \ingroup group__library__filesystem
  463. */
  464. typedef basic_path<ws_char_w_t, filesystem_traits<ws_char_w_t> > path_w;
  465. /** Specialisation of the basic_path template for the Win32 character type \c TCHAR
  466. *
  467. * \ingroup group__library__filesystem
  468. */
  469. typedef basic_path<TCHAR, filesystem_traits<TCHAR> > path;
  470. /* /////////////////////////////////////////////////////////////////////////
  471. * Support for PlatformSTL redefinition by inheritance+namespace, for confused
  472. * compilers (e.g. VC++ 6)
  473. */
  474. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  475. template< ss_typename_param_k C
  476. # ifdef STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT
  477. , ss_typename_param_k T = filesystem_traits<C>
  478. , ss_typename_param_k A = processheap_allocator<C>
  479. # else /* ? STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT */
  480. , ss_typename_param_k T /* = filesystem_traits<C> */
  481. , ss_typename_param_k A /* = processheap_allocator<C> */
  482. # endif /* STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT */
  483. >
  484. class basic_path__
  485. : public winstl_ns_qual(basic_path)<C, T, A>
  486. {
  487. private:
  488. typedef winstl_ns_qual(basic_path)<C, T, A> parent_class_type;
  489. typedef winstl_ns_qual(basic_path__)<C, T, A> class_type;
  490. public:
  491. typedef ss_typename_type_k parent_class_type::char_type char_type;
  492. typedef ss_typename_type_k parent_class_type::traits_type traits_type;
  493. typedef ss_typename_type_k parent_class_type::allocator_type allocator_type;
  494. typedef ss_typename_type_k parent_class_type::size_type size_type;
  495. public:
  496. basic_path__()
  497. : parent_class_type()
  498. {}
  499. ss_explicit_k basic_path__(char_type const* path)
  500. : parent_class_type(path)
  501. {}
  502. # ifdef STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT
  503. /// Constructs a path from \c path
  504. template<ss_typename_param_k S>
  505. ss_explicit_k basic_path__(S const& s)
  506. : parent_class_type(s)
  507. {}
  508. # endif /* STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT */
  509. basic_path__(char_type const* path, size_type cch)
  510. : parent_class_type(path, cch)
  511. {}
  512. basic_path__(class_type const& rhs)
  513. : parent_class_type(rhs)
  514. {}
  515. class_type& operator =(class_type const& rhs)
  516. {
  517. parent_class_type::operator =(rhs);
  518. return *this;
  519. }
  520. class_type& operator =(char_type const* rhs)
  521. {
  522. parent_class_type::operator =(rhs);
  523. return *this;
  524. }
  525. # ifdef STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT
  526. template<ss_typename_param_k S>
  527. class_type& operator =(S const& s)
  528. {
  529. parent_class_type::operator =(s);
  530. return *this;
  531. }
  532. # endif /* STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT */
  533. };
  534. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  535. /* /////////////////////////////////////////////////////////////////////////
  536. * Operators
  537. */
  538. template< ss_typename_param_k C
  539. , ss_typename_param_k T
  540. , ss_typename_param_k A
  541. >
  542. inline ws_bool_t operator ==(basic_path<C, T, A> const& lhs, ss_typename_type_k basic_path<C, T, A>::char_type const* rhs)
  543. {
  544. return lhs.equal(rhs);
  545. }
  546. template< ss_typename_param_k C
  547. , ss_typename_param_k T
  548. , ss_typename_param_k A
  549. >
  550. inline ws_bool_t operator !=(basic_path<C, T, A> const& lhs, ss_typename_type_k basic_path<C, T, A>::char_type const* rhs)
  551. {
  552. return !lhs.equal(rhs);
  553. }
  554. template< ss_typename_param_k C
  555. , ss_typename_param_k T
  556. , ss_typename_param_k A
  557. >
  558. inline ws_bool_t operator ==(ss_typename_type_k basic_path<C, T, A>::char_type const* lhs, basic_path<C, T, A> const& rhs)
  559. {
  560. return rhs.equal(lhs);
  561. }
  562. template< ss_typename_param_k C
  563. , ss_typename_param_k T
  564. , ss_typename_param_k A
  565. >
  566. inline ws_bool_t operator !=(ss_typename_type_k basic_path<C, T, A>::char_type const* lhs, basic_path<C, T, A> const& rhs)
  567. {
  568. return !rhs.equal(lhs);
  569. }
  570. template< ss_typename_param_k C
  571. , ss_typename_param_k T
  572. , ss_typename_param_k A
  573. >
  574. inline ws_bool_t operator ==(basic_path<C, T, A> const& lhs, basic_path<C, T, A> const& rhs)
  575. {
  576. return lhs.equal(rhs);
  577. }
  578. template< ss_typename_param_k C
  579. , ss_typename_param_k T
  580. , ss_typename_param_k A
  581. >
  582. inline ws_bool_t operator !=(basic_path<C, T, A> const& lhs, basic_path<C, T, A> const& rhs)
  583. {
  584. return !lhs.equal(rhs);
  585. }
  586. // operator /
  587. /** Concatenates \c rhs to the path \c lhs
  588. *
  589. * \ingroup group__library__filesystem
  590. */
  591. template< ss_typename_param_k C
  592. , ss_typename_param_k T
  593. , ss_typename_param_k A
  594. >
  595. inline basic_path<C, T, A> operator /(basic_path<C, T, A> const& lhs, ss_typename_type_k basic_path<C, T, A>::char_type const* rhs)
  596. {
  597. return basic_path<C, T, A>(lhs) /= rhs;
  598. }
  599. /** Concatenates \c rhs to the path \c lhs
  600. *
  601. * \ingroup group__library__filesystem
  602. */
  603. template< ss_typename_param_k C
  604. , ss_typename_param_k T
  605. , ss_typename_param_k A
  606. >
  607. inline basic_path<C, T, A> operator /(ss_typename_type_k basic_path<C, T, A>::char_type const* lhs, basic_path<C, T, A> const& rhs)
  608. {
  609. return basic_path<C, T, A>(lhs) /= rhs;
  610. }
  611. /** Concatenates \c rhs to the path \c lhs
  612. *
  613. * \ingroup group__library__filesystem
  614. */
  615. template< ss_typename_param_k C
  616. , ss_typename_param_k T
  617. , ss_typename_param_k A
  618. >
  619. inline basic_path<C, T, A> operator /(basic_path<C, T, A> const& lhs, basic_path<C, T, A> const& rhs)
  620. {
  621. return basic_path<C, T, A>(lhs) /= rhs;
  622. }
  623. /* /////////////////////////////////////////////////////////////////////////
  624. * Helper functions
  625. */
  626. #if !defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  627. # if !defined(STLSOFT_COMPILER_IS_MSVC) || \
  628. _MSC_VER >= 1100
  629. /** This helper function makes a path variable without needing to
  630. * qualify the template parameter.
  631. *
  632. * \ingroup group__library__filesystem
  633. */
  634. template<ss_typename_param_k C>
  635. inline basic_path<C> make_path(C const* path)
  636. {
  637. return basic_path<C>(path);
  638. }
  639. # endif /* compiler */
  640. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  641. /* /////////////////////////////////////////////////////////////////////////
  642. * swapping
  643. */
  644. template< ss_typename_param_k C
  645. , ss_typename_param_k T
  646. , ss_typename_param_k A
  647. >
  648. inline void swap(basic_path<C, T, A>& lhs, basic_path<C, T, A>& rhs)
  649. {
  650. lhs.swap(rhs);
  651. }
  652. /* /////////////////////////////////////////////////////////////////////////
  653. * Shims
  654. */
  655. /** \ref group__concept__shim__string_access__c_str_data for winstl::basic_path
  656. *
  657. * \ingroup group__concept__shim__string_access
  658. */
  659. template< ss_typename_param_k C
  660. , ss_typename_param_k T
  661. , ss_typename_param_k A
  662. >
  663. inline C const* c_str_data(winstl_ns_qual(basic_path)<C, T, A> const& b)
  664. {
  665. return b.c_str();
  666. }
  667. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  668. template <ss_typename_param_k T, ss_typename_param_k A>
  669. inline ws_char_a_t const* c_str_data_a(winstl_ns_qual(basic_path)<ws_char_a_t, T, A> const& b)
  670. {
  671. return b.c_str();
  672. }
  673. template <ss_typename_param_k T, ss_typename_param_k A>
  674. inline ws_char_w_t const* c_str_data_w(winstl_ns_qual(basic_path)<ws_char_w_t, T, A> const& b)
  675. {
  676. return b.c_str();
  677. }
  678. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  679. /** \ref group__concept__shim__string_access__c_str_len for winstl::basic_path
  680. *
  681. * \ingroup group__concept__shim__string_access
  682. */
  683. template< ss_typename_param_k C
  684. , ss_typename_param_k T
  685. , ss_typename_param_k A
  686. >
  687. inline ws_size_t c_str_len(winstl_ns_qual(basic_path)<C, T, A> const& b)
  688. {
  689. return stlsoft_ns_qual(c_str_len)(b.c_str());
  690. }
  691. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  692. template <ss_typename_param_k T, ss_typename_param_k A>
  693. inline ws_size_t c_str_len_a(winstl_ns_qual(basic_path)<ws_char_a_t, T, A> const& b)
  694. {
  695. return stlsoft_ns_qual(c_str_len_a)(b.c_str());
  696. }
  697. template <ss_typename_param_k T, ss_typename_param_k A>
  698. inline ws_size_t c_str_len_w(winstl_ns_qual(basic_path)<ws_char_w_t, T, A> const& b)
  699. {
  700. return stlsoft_ns_qual(c_str_len_w)(b.c_str());
  701. }
  702. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  703. /** \ref group__concept__shim__string_access__c_str_ptr for winstl::basic_path
  704. *
  705. * \ingroup group__concept__shim__string_access
  706. */
  707. template< ss_typename_param_k C
  708. , ss_typename_param_k T
  709. , ss_typename_param_k A
  710. >
  711. inline C const* c_str_ptr(winstl_ns_qual(basic_path)<C, T, A> const& b)
  712. {
  713. return b.c_str();
  714. }
  715. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  716. template <ss_typename_param_k T, ss_typename_param_k A>
  717. inline ws_char_a_t const* c_str_ptr_a(winstl_ns_qual(basic_path)<ws_char_a_t, T, A> const& b)
  718. {
  719. return b.c_str();
  720. }
  721. template <ss_typename_param_k T, ss_typename_param_k A>
  722. inline ws_char_w_t const* c_str_ptr_w(winstl_ns_qual(basic_path)<ws_char_w_t, T, A> const& b)
  723. {
  724. return b.c_str();
  725. }
  726. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  727. /** \ref group__concept__shim__string_access__c_str_ptr_null for winstl::basic_path
  728. *
  729. * \ingroup group__concept__shim__string_access
  730. */
  731. template< ss_typename_param_k C
  732. , ss_typename_param_k T
  733. , ss_typename_param_k A
  734. >
  735. inline C const* c_str_ptr_null(winstl_ns_qual(basic_path)<C, T, A> const& b)
  736. {
  737. return stlsoft_ns_qual(c_str_ptr_null)(b.c_str());
  738. }
  739. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  740. template <ss_typename_param_k T, ss_typename_param_k A>
  741. inline ws_char_a_t const* c_str_ptr_null_a(winstl_ns_qual(basic_path)<ws_char_a_t, T, A> const& b)
  742. {
  743. return stlsoft_ns_qual(c_str_ptr_null_a)(b.c_str());
  744. }
  745. template <ss_typename_param_k T, ss_typename_param_k A>
  746. inline ws_char_w_t const* c_str_ptr_null_w(winstl_ns_qual(basic_path)<ws_char_w_t, T, A> const& b)
  747. {
  748. return stlsoft_ns_qual(c_str_ptr_null_w)(b.c_str());
  749. }
  750. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  751. /** \ref group__concept__shim__stream_insertion "stream insertion shim" for winstl::basic_path
  752. *
  753. * \ingroup group__concept__shim__stream_insertion
  754. */
  755. template< ss_typename_param_k S
  756. , ss_typename_param_k C
  757. , ss_typename_param_k T
  758. , ss_typename_param_k A
  759. >
  760. inline S& operator <<(S& s, winstl_ns_qual(basic_path)<C, T, A> const& b)
  761. {
  762. s << b.c_str();
  763. return s;
  764. }
  765. ////////////////////////////////////////////////////////////////////////////
  766. // Unit-testing
  767. #ifdef STLSOFT_UNITTEST
  768. # include "./unittest/path_unittest_.h"
  769. #endif /* STLSOFT_UNITTEST */
  770. ////////////////////////////////////////////////////////////////////////////
  771. // Implementation
  772. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  773. template< ss_typename_param_k C
  774. , ss_typename_param_k T
  775. , ss_typename_param_k A
  776. >
  777. inline /* static */ ss_typename_param_k basic_path<C, T, A>::bool_type
  778. basic_path<C, T, A>::has_dir_end_() const
  779. {
  780. return empty() ? false : traits_type::has_dir_end(m_buffer.c_str() + (m_len - 1));
  781. }
  782. template< ss_typename_param_k C
  783. , ss_typename_param_k T
  784. , ss_typename_param_k A
  785. >
  786. inline /* static */ ss_typename_param_k basic_path<C, T, A>::char_type const*
  787. basic_path<C, T, A>::last_slash_(
  788. ss_typename_param_k basic_path<C, T, A>::char_type const* buffer
  789. , ss_typename_param_k basic_path<C, T, A>::size_type /* len */
  790. )
  791. {
  792. char_type* slash = traits_type::str_rchr(buffer, path_name_separator());
  793. char_type* slash_a = traits_type::str_rchr(buffer, path_name_separator_alt());
  794. if(slash_a > slash)
  795. {
  796. slash = slash_a;
  797. }
  798. return slash;
  799. }
  800. template< ss_typename_param_k C
  801. , ss_typename_param_k T
  802. , ss_typename_param_k A
  803. >
  804. inline /* static */ ss_typename_param_k basic_path<C, T, A>::char_type const* basic_path<C, T, A>::next_slash_or_end(ss_typename_param_k basic_path<C, T, A>::char_type const* p)
  805. {
  806. for(; ; )
  807. {
  808. switch(*p)
  809. {
  810. case '/':
  811. case '\\':
  812. case '\0':
  813. return p;
  814. default:
  815. ++p;
  816. break;
  817. }
  818. }
  819. }
  820. template< ss_typename_param_k C
  821. , ss_typename_param_k T
  822. , ss_typename_param_k A
  823. >
  824. inline /* static */ ss_typename_param_k basic_path<C, T, A>::char_type const* basic_path<C, T, A>::next_part_or_end(ss_typename_param_k basic_path<C, T, A>::char_type const* p)
  825. {
  826. for(; ; )
  827. {
  828. switch(*p)
  829. {
  830. case '/':
  831. case '\\':
  832. ++p;
  833. case '\0':
  834. return p;
  835. default:
  836. ++p;
  837. break;
  838. }
  839. }
  840. }
  841. template< ss_typename_param_k C
  842. , ss_typename_param_k T
  843. , ss_typename_param_k A
  844. >
  845. inline /* static */ ss_typename_param_k basic_path<C, T, A>::char_type basic_path<C, T, A>::path_name_separator_alt()
  846. {
  847. return '/';
  848. }
  849. template <ss_typename_param_k C, ss_typename_param_k T, ss_typename_param_k A>
  850. inline /* static */ ss_typename_param_k basic_path<C, T, A>::char_type
  851. basic_path<C, T, A>::path_name_separator()
  852. {
  853. WINSTL_ASSERT('\\' == traits_type::path_name_separator());
  854. return '\\';
  855. }
  856. template< ss_typename_param_k C
  857. , ss_typename_param_k T
  858. , ss_typename_param_k A
  859. >
  860. inline void basic_path<C, T, A>::swap(basic_path<C, T, A>& rhs)
  861. {
  862. m_buffer.swap(rhs.m_buffer);
  863. std_swap(m_len, rhs.m_len);
  864. }
  865. template< ss_typename_param_k C
  866. , ss_typename_param_k T
  867. , ss_typename_param_k A
  868. >
  869. inline
  870. ss_typename_param_k basic_path<C, T, A>::class_type&
  871. basic_path<C, T, A>::concat_(
  872. ss_typename_param_k basic_path<C, T, A>::char_type const* rhs
  873. , ss_typename_param_k basic_path<C, T, A>::size_type cch
  874. )
  875. {
  876. traits_type::char_copy(&m_buffer[0] + m_len, rhs, cch);
  877. m_len += cch;
  878. m_buffer[m_len] = '\0';
  879. return *this;
  880. }
  881. template< ss_typename_param_k C
  882. , ss_typename_param_k T
  883. , ss_typename_param_k A
  884. >
  885. inline /* static */ ss_typename_param_k basic_path<C, T, A>::size_type basic_path<C, T, A>::coalesce_parts_(ss_typename_param_k basic_path<C, T, A>::part_buffer_type_& parts)
  886. {
  887. ss_typename_param_k part_buffer_type_::iterator src = parts.begin();
  888. ss_typename_param_k part_buffer_type_::iterator dest = parts.begin();
  889. { for(size_type i = 0; i < parts.size(); ++i, ++src)
  890. {
  891. if(0 == parts[i].len)
  892. {
  893. ; // Skip/overwrite this element
  894. }
  895. else
  896. {
  897. if(dest != src)
  898. {
  899. *dest = *src;
  900. }
  901. ++dest;
  902. }
  903. }}
  904. size_type n = static_cast<size_type>(dest - parts.begin());
  905. parts.resize(n);
  906. return n;
  907. }
  908. template< ss_typename_param_k C
  909. , ss_typename_param_k T
  910. , ss_typename_param_k A
  911. >
  912. inline basic_path<C, T, A>::basic_path()
  913. : m_len(0)
  914. {
  915. m_buffer[0] = '\0';
  916. }
  917. template< ss_typename_param_k C
  918. , ss_typename_param_k T
  919. , ss_typename_param_k A
  920. >
  921. inline /* ss_explicit_k */ basic_path<C, T, A>::basic_path(ss_typename_type_k basic_path<C, T, A>::char_type const* path)
  922. : m_len(0)
  923. {
  924. if(NULL != path)
  925. {
  926. size_type cch = traits_type::str_len(path);
  927. WINSTL_MESSAGE_ASSERT("path too long", cch < m_buffer.size());
  928. traits_type::char_copy(&m_buffer[0], path, cch);
  929. m_len = cch;
  930. }
  931. m_buffer[m_len] = '\0';
  932. }
  933. template< ss_typename_param_k C
  934. , ss_typename_param_k T
  935. , ss_typename_param_k A
  936. >
  937. inline basic_path<C, T, A>::basic_path(ss_typename_type_k basic_path<C, T, A>::char_type const* path, ss_typename_type_k basic_path<C, T, A>::size_type cch)
  938. : m_len(cch)
  939. {
  940. WINSTL_ASSERT((NULL != path) || (0 == cch));
  941. if(0 != cch)
  942. {
  943. WINSTL_MESSAGE_ASSERT("path too long", cch < m_buffer.size());
  944. traits_type::char_copy(&m_buffer[0], path, cch);
  945. }
  946. m_buffer[cch] = '\0';
  947. }
  948. #ifndef STLSOFT_CF_NO_COPY_CTOR_AND_COPY_CTOR_TEMPLATE_OVERLOAD
  949. template< ss_typename_param_k C
  950. , ss_typename_param_k T
  951. , ss_typename_param_k A
  952. >
  953. inline basic_path<C, T, A>::basic_path(basic_path<C, T, A> const& rhs)
  954. : m_len(rhs.m_len)
  955. {
  956. traits_type::char_copy(&m_buffer[0], rhs.m_buffer.c_str(), rhs.m_len + 1); // +1 to get the NUL terminator
  957. }
  958. #endif /* !STLSOFT_CF_NO_COPY_CTOR_AND_COPY_CTOR_TEMPLATE_OVERLOAD */
  959. #ifndef STLSOFT_CF_NO_COPY_CTOR_AND_COPY_CTOR_TEMPLATE_OVERLOAD
  960. template< ss_typename_param_k C
  961. , ss_typename_param_k T
  962. , ss_typename_param_k A
  963. >
  964. inline basic_path<C, T, A>& basic_path<C, T, A>::operator =(basic_path<C, T, A> const& path)
  965. {
  966. class_type newPath(path);
  967. swap(newPath);
  968. return *this;
  969. }
  970. #endif /* !STLSOFT_CF_NO_COPY_CTOR_AND_COPY_CTOR_TEMPLATE_OVERLOAD */
  971. template< ss_typename_param_k C
  972. , ss_typename_param_k T
  973. , ss_typename_param_k A
  974. >
  975. inline basic_path<C, T, A>& basic_path<C, T, A>::operator =(ss_typename_type_k basic_path<C, T, A>::char_type const* path)
  976. {
  977. return operator_equal_(path);
  978. }
  979. template< ss_typename_param_k C
  980. , ss_typename_param_k T
  981. , ss_typename_param_k A
  982. >
  983. inline basic_path<C, T, A>& basic_path<C, T, A>::operator_equal_(ss_typename_type_k basic_path<C, T, A>::char_type const* path)
  984. {
  985. class_type newPath(path);
  986. swap(newPath);
  987. return *this;
  988. }
  989. template< ss_typename_param_k C
  990. , ss_typename_param_k T
  991. , ss_typename_param_k A
  992. >
  993. inline /* static */ ss_typename_type_ret_k basic_path<C, T, A>::class_type basic_path<C, T, A>::root(ss_typename_type_k basic_path<C, T, A>::char_type const* s)
  994. {
  995. return class_type(s);
  996. }
  997. template< ss_typename_param_k C
  998. , ss_typename_param_k T
  999. , ss_typename_param_k A
  1000. >
  1001. inline basic_path<C, T, A>& basic_path<C, T, A>::push(class_type const& rhs, ws_bool_t bAddPathNameSeparator /* = false */)
  1002. {
  1003. // TODO: Change to use data(), when push_() properly implemented
  1004. return push_(rhs.c_str(), rhs.size(), bAddPathNameSeparator);
  1005. }
  1006. template< ss_typename_param_k C
  1007. , ss_typename_param_k T
  1008. , ss_typename_param_k A
  1009. >
  1010. inline basic_path<C, T, A>& basic_path<C, T, A>::push(char_type const* rhs, ws_bool_t bAddPathNameSeparator /* = false */)
  1011. {
  1012. WINSTL_ASSERT(NULL != rhs);
  1013. return push_(rhs, traits_type::str_len(rhs), bAddPathNameSeparator);
  1014. }
  1015. template< ss_typename_param_k C
  1016. , ss_typename_param_k T
  1017. , ss_typename_param_k A
  1018. >
  1019. inline basic_path<C, T, A>&
  1020. basic_path<C, T, A>::push_(
  1021. char_type const* rhs
  1022. , size_type cch
  1023. , ws_bool_t bAddPathNameSeparator
  1024. )
  1025. {
  1026. if(0 != cch)
  1027. {
  1028. if(traits_type::is_path_rooted(rhs))
  1029. {
  1030. class_type newPath(rhs, cch);
  1031. if( bAddPathNameSeparator &&
  1032. !newPath.has_dir_end_())
  1033. {
  1034. newPath.push_sep();
  1035. }
  1036. swap(newPath);
  1037. }
  1038. else
  1039. {
  1040. WINSTL_MESSAGE_ASSERT("path too long", size() + 1 + cch < m_buffer.size());
  1041. // In an attempt to maintain slash/backslash consistency, we
  1042. // locate the next slash to help guide the push_sep_() method.
  1043. class_type newPath(*this);
  1044. char_type const* psep = next_slash_or_end(c_str());
  1045. char_type sep = ('\0' == *psep) ? char_type(0) : psep[0];
  1046. newPath.push_sep_(sep);
  1047. newPath.concat_(rhs, cch);
  1048. if(bAddPathNameSeparator)
  1049. {
  1050. newPath.push_sep();
  1051. }
  1052. swap(newPath);
  1053. }
  1054. }
  1055. return *this;
  1056. }
  1057. #if 0
  1058. template< ss_typename_param_k C
  1059. , ss_typename_param_k T
  1060. , ss_typename_param_k A
  1061. >
  1062. inline basic_path<C, T, A>& basic_path<C, T, A>::push_ext(class_type const& rhs, ws_bool_t bAddPathNameSeparator /* = false */)
  1063. {
  1064. }
  1065. #endif /* 0 */
  1066. template< ss_typename_param_k C
  1067. , ss_typename_param_k T
  1068. , ss_typename_param_k A
  1069. >
  1070. inline basic_path<C, T, A>& basic_path<C, T, A>::push_ext(char_type const* rhs, ws_bool_t bAddPathNameSeparator /* = false */)
  1071. {
  1072. WINSTL_ASSERT(NULL != rhs);
  1073. class_type newPath(*this);
  1074. newPath.pop_sep();
  1075. if('.' != *rhs)
  1076. {
  1077. static char_type const s_dot[] = { '.', '\0' };
  1078. newPath.concat_(s_dot, 1u);
  1079. }
  1080. newPath.concat_(rhs, traits_type::str_len(rhs));
  1081. if(bAddPathNameSeparator)
  1082. {
  1083. newPath.push_sep();
  1084. }
  1085. swap(newPath);
  1086. return *this;
  1087. }
  1088. template< ss_typename_param_k C
  1089. , ss_typename_param_k T
  1090. , ss_typename_param_k A
  1091. >
  1092. inline basic_path<C, T, A>& basic_path<C, T, A>::push_sep()
  1093. {
  1094. char_type sep = path_name_separator();
  1095. char_type* slash = traits_type::str_chr(m_buffer.c_str(), path_name_separator());
  1096. char_type* slash_a = traits_type::str_chr(m_buffer.c_str(), path_name_separator_alt());
  1097. if( NULL == slash &&
  1098. NULL != slash_a)
  1099. {
  1100. sep = path_name_separator_alt();
  1101. }
  1102. return push_sep_(sep);
  1103. }
  1104. template< ss_typename_param_k C
  1105. , ss_typename_param_k T
  1106. , ss_typename_param_k A
  1107. >
  1108. inline basic_path<C, T, A>& basic_path<C, T, A>::push_sep_(ss_typename_type_k basic_path<C, T, A>::char_type sep)
  1109. {
  1110. if(0 == sep)
  1111. {
  1112. sep = path_name_separator();
  1113. }
  1114. WINSTL_MESSAGE_ASSERT("You can only push a path name separator character recognised by your operating system!", traits_type::is_path_name_separator(sep));
  1115. if(0 != m_len)
  1116. {
  1117. char_type& last = m_buffer[m_len - 1];
  1118. if(traits_type::is_path_name_separator(last))
  1119. {
  1120. if(last != sep)
  1121. {
  1122. last = sep;
  1123. }
  1124. }
  1125. else
  1126. {
  1127. WINSTL_ASSERT(m_len + 1 < m_buffer.size());
  1128. m_buffer[m_len] = sep;
  1129. m_buffer[m_len + 1] = '\0';
  1130. ++m_len;
  1131. }
  1132. }
  1133. return *this;
  1134. }
  1135. template< ss_typename_param_k C
  1136. , ss_typename_param_k T
  1137. , ss_typename_param_k A
  1138. >
  1139. inline basic_path<C, T, A>& basic_path<C, T, A>::pop(ws_bool_t bRemoveTrailingPathNameSeparator /* = true */)
  1140. {
  1141. char_type* slash = const_cast<char_type*>(last_slash_(m_buffer.data(), m_len));
  1142. if(NULL != slash)
  1143. {
  1144. if(static_cast<size_type>(slash - m_buffer.data()) + 1 == m_len)
  1145. {
  1146. bool shouldRemoveTrailingSlash = true;
  1147. // The last slash is just a trailing separator
  1148. //
  1149. // Is it just a volume, or just a UNC, or just a root slash
  1150. if(traits_type::is_path_rooted(m_buffer.c_str()))
  1151. {
  1152. if(traits_type::is_path_UNC(m_buffer.c_str()))
  1153. {
  1154. char_type const* share = next_part_or_end(m_buffer.c_str() + 2);
  1155. if(NULL == share)
  1156. {
  1157. shouldRemoveTrailingSlash = false;
  1158. }
  1159. }
  1160. else if(traits_type::is_path_absolute(m_buffer.c_str()))
  1161. {
  1162. if(3 == m_len)
  1163. {
  1164. shouldRemoveTrailingSlash = false;
  1165. }
  1166. }
  1167. else
  1168. {
  1169. if(1 == m_len)
  1170. {
  1171. shouldRemoveTrailingSlash = false;
  1172. }
  1173. }
  1174. }
  1175. if(shouldRemoveTrailingSlash)
  1176. {
  1177. m_buffer[--m_len] = '\0';
  1178. slash = const_cast<char_type*>(last_slash_(m_buffer.data(), m_len));
  1179. }
  1180. }
  1181. }
  1182. if(NULL != slash)
  1183. {
  1184. if(traits_type::is_path_UNC(m_buffer.c_str()))
  1185. {
  1186. char_type const* shareSlash = next_slash_or_end(m_buffer.c_str() + 2);
  1187. if(shareSlash == slash)
  1188. {
  1189. slash = NULL;
  1190. }
  1191. }
  1192. else if(traits_type::is_path_absolute(m_buffer.c_str()) &&
  1193. 3 == m_len)
  1194. {
  1195. slash = NULL;
  1196. }
  1197. else if(traits_type::is_path_rooted(m_buffer.c_str()) &&
  1198. 1 == m_len)
  1199. {
  1200. slash = NULL;
  1201. }
  1202. }
  1203. if(NULL != slash)
  1204. {
  1205. *(slash + 1) = '\0';
  1206. m_len = static_cast<size_type>((slash + 1) - m_buffer.c_str());
  1207. if(bRemoveTrailingPathNameSeparator)
  1208. {
  1209. this->pop_sep();
  1210. }
  1211. }
  1212. if(NULL == slash)
  1213. {
  1214. clear();
  1215. }
  1216. return *this;
  1217. }
  1218. template< ss_typename_param_k C
  1219. , ss_typename_param_k T
  1220. , ss_typename_param_k A
  1221. >
  1222. inline basic_path<C, T, A>& basic_path<C, T, A>::pop_sep() stlsoft_throw_0()
  1223. {
  1224. if(0 != m_len)
  1225. {
  1226. if( 1 == m_len &&
  1227. traits_type::is_path_name_separator(m_buffer[0]))
  1228. {
  1229. // It's / or \ - ignore
  1230. }
  1231. else if(3 == m_len &&
  1232. ':' == m_buffer[1] &&
  1233. traits_type::is_path_name_separator(m_buffer[2]))
  1234. {
  1235. // It's drive rooted - ignore
  1236. }
  1237. else
  1238. {
  1239. // We can pop a separator off anything else, including a UNC host
  1240. char_type* last = &m_buffer[m_len - 1];
  1241. if(*last == path_name_separator())
  1242. {
  1243. m_buffer[m_len-- - 1] = '\0';
  1244. }
  1245. else if(*last == path_name_separator_alt())
  1246. {
  1247. m_buffer[m_len-- - 1] = '\0';
  1248. }
  1249. }
  1250. }
  1251. return *this;
  1252. }
  1253. template< ss_typename_param_k C
  1254. , ss_typename_param_k T
  1255. , ss_typename_param_k A
  1256. >
  1257. inline basic_path<C, T, A>& basic_path<C, T, A>::pop_ext() stlsoft_throw_0()
  1258. {
  1259. { for(ws_size_t len = m_len; 0 != len; --len)
  1260. {
  1261. char_type* last = &m_buffer[len - 1];
  1262. if(traits_type::is_path_name_separator(*last))
  1263. {
  1264. break;
  1265. }
  1266. else if('.' == *last)
  1267. {
  1268. m_len = len - 1;
  1269. m_buffer[m_len] = '\0';
  1270. break;
  1271. }
  1272. }}
  1273. return *this;
  1274. }
  1275. #if !defined(STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT) || \
  1276. defined(STLSOFT_CF_MEMBER_TEMPLATE_OVERLOAD_DISCRIMINATED)
  1277. template< ss_typename_param_k C
  1278. , ss_typename_param_k T
  1279. , ss_typename_param_k A
  1280. >
  1281. inline basic_path<C, T, A>& basic_path<C, T, A>::operator /=(basic_path<C, T, A> const& path)
  1282. {
  1283. return push(path);
  1284. }
  1285. #endif /* !STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT || STLSOFT_CF_MEMBER_TEMPLATE_OVERLOAD_DISCRIMINATED */
  1286. template< ss_typename_param_k C
  1287. , ss_typename_param_k T
  1288. , ss_typename_param_k A
  1289. >
  1290. inline basic_path<C, T, A>& basic_path<C, T, A>::operator /=(ss_typename_type_k basic_path<C, T, A>::char_type const* path)
  1291. {
  1292. return push(path);
  1293. }
  1294. template< ss_typename_param_k C
  1295. , ss_typename_param_k T
  1296. , ss_typename_param_k A
  1297. >
  1298. inline void basic_path<C, T, A>::clear()
  1299. {
  1300. m_buffer[0] = '\0';
  1301. m_len = 0;
  1302. }
  1303. template< ss_typename_param_k C
  1304. , ss_typename_param_k T
  1305. , ss_typename_param_k A
  1306. >
  1307. inline basic_path<C, T, A>& basic_path<C, T, A>::make_absolute(ws_bool_t bRemoveTrailingPathNameSeparator /* = true */)
  1308. {
  1309. if(0 != size())
  1310. {
  1311. buffer_type_ buffer;
  1312. size_type cch = traits_type::get_full_path_name(c_str(), buffer.size(), &buffer[0]);
  1313. if(0 == cch)
  1314. {
  1315. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  1316. STLSOFT_THROW_X(windows_exception("could not determine the absolute path", ::GetLastError()));
  1317. #else /* ?STLSOFT_CF_EXCEPTION_SUPPORT */
  1318. return *this;
  1319. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  1320. }
  1321. class_type newPath(buffer.c_str(), cch);
  1322. if(bRemoveTrailingPathNameSeparator)
  1323. {
  1324. newPath.pop_sep();
  1325. }
  1326. swap(newPath);
  1327. }
  1328. return *this;
  1329. }
  1330. template< ss_typename_param_k C
  1331. , ss_typename_param_k T
  1332. , ss_typename_param_k A
  1333. >
  1334. inline basic_path<C, T, A>& basic_path<C, T, A>::canonicalise(ws_bool_t bRemoveTrailingPathNameSeparator /* = true */)
  1335. {
  1336. if(0 == size())
  1337. {
  1338. return *this;
  1339. }
  1340. class_type newPath(*this);
  1341. #ifdef _DEBUG
  1342. memset(&newPath.m_buffer[0], '~', newPath.m_buffer.size());
  1343. #endif /* _DEBUG */
  1344. // Basically we scan through the path looking for ./ .\ ..\ and ../
  1345. // 0. Handle special path prefixes
  1346. part_buffer_type_ parts(this->length() / 2); // Uncanonicalised directory parts
  1347. char_type* dest = &newPath.m_buffer[0];
  1348. char_type const* p1 = this->c_str();
  1349. char_type const* p2;
  1350. if(traits_type::is_path_UNC(this->c_str()))
  1351. {
  1352. WINSTL_ASSERT('\\' == m_buffer[0]);
  1353. WINSTL_ASSERT('\\' == m_buffer[1]);
  1354. WINSTL_ASSERT('\\' != m_buffer[2]);
  1355. char_type const* slash0 = next_slash_or_end(&m_buffer[3]);
  1356. char_type const* slash1 = next_slash_or_end(slash0);
  1357. for(ws_size_t i = 0, n = static_cast<ws_size_t>(slash1 - &m_buffer[0]); i < n; ++i)
  1358. {
  1359. *dest++ = *p1++;
  1360. }
  1361. }
  1362. else if(this->is_absolute())
  1363. {
  1364. // Copy over the drive letter, colon and slash
  1365. *dest++ = *p1++;
  1366. *dest++ = *p1++;
  1367. *dest++ = *p1++;
  1368. }
  1369. else if(this->is_rooted())
  1370. {
  1371. *dest++ = path_name_separator();
  1372. ++p1;
  1373. }
  1374. // 1. Parse the path into an uncanonicalised sequence of directory parts
  1375. {
  1376. size_type i = 0;
  1377. for(; '\0' != *p1; ++i)
  1378. {
  1379. p2 = next_part_or_end(p1);
  1380. parts[i].len = static_cast<size_type>(p2 - p1);
  1381. parts[i].p = p1;
  1382. parts[i].type = part_type::normal;
  1383. switch(parts[i].len)
  1384. {
  1385. case 1:
  1386. if('.' == p1[0])
  1387. {
  1388. parts[i].type = part_type::dot;
  1389. }
  1390. break;
  1391. case 2:
  1392. if('.' == p1[0])
  1393. {
  1394. if('.' == p1[1])
  1395. {
  1396. parts[i].type = part_type::dotdot;
  1397. }
  1398. else if(path_name_separator() == p1[1])
  1399. {
  1400. parts[i].type = part_type::dot;
  1401. }
  1402. else if(path_name_separator_alt() == p1[1])
  1403. {
  1404. parts[i].type = part_type::dot;
  1405. }
  1406. }
  1407. break;
  1408. case 3:
  1409. if( '.' == p1[0] &&
  1410. '.' == p1[1])
  1411. {
  1412. if(path_name_separator() == p1[2])
  1413. {
  1414. parts[i].type = part_type::dotdot;
  1415. }
  1416. else if(path_name_separator_alt() == p1[2])
  1417. {
  1418. parts[i].type = part_type::dotdot;
  1419. }
  1420. }
  1421. break;
  1422. default:
  1423. break;
  1424. }
  1425. p1 = p2;
  1426. }
  1427. parts.resize(i);
  1428. }
  1429. // 2.a Remove all '.' parts
  1430. { for(size_type i = 0; i < parts.size(); ++i)
  1431. {
  1432. WINSTL_ASSERT(0 != parts[i].len);
  1433. part_type& part = parts[i];
  1434. if(part_type::dot == part.type)
  1435. {
  1436. part.len = 0;
  1437. }
  1438. }}
  1439. coalesce_parts_(parts);
  1440. // 2.b Process the '..' parts
  1441. { for(size_type i = 1; i < parts.size(); ++i)
  1442. {
  1443. WINSTL_ASSERT(0 != parts[i].len);
  1444. part_type& part = parts[i];
  1445. if(part_type::dotdot == part.type)
  1446. {
  1447. { for(size_type prior = i; ; )
  1448. {
  1449. if(0 == prior)
  1450. {
  1451. break;
  1452. }
  1453. else
  1454. {
  1455. --prior;
  1456. if(0 != parts[prior].len)
  1457. {
  1458. if(part_type::normal == parts[prior].type)
  1459. {
  1460. part.len = 0;
  1461. parts[prior].len = 0;
  1462. break;
  1463. }
  1464. }
  1465. }
  1466. }}
  1467. }
  1468. }}
  1469. coalesce_parts_(parts);
  1470. // 2.c "insert" a '.' if we've removed everything.
  1471. if( !this->is_rooted() &&
  1472. parts.empty())
  1473. {
  1474. static const char_type s_dot[] = { '.', '/' };
  1475. parts.resize(1);
  1476. parts[0].type = part_type::dot;
  1477. parts[0].len = 1;
  1478. parts[0].p = s_dot;
  1479. }
  1480. // 3. Write out all the parts back into the new path instance
  1481. {
  1482. #ifdef _DEBUG
  1483. ::memset(dest, '~', newPath.m_buffer.size() - (dest - &newPath.m_buffer[0]));
  1484. #endif /* _DEBUG */
  1485. for(size_type i = 0; i < parts.size(); ++i)
  1486. {
  1487. traits_type::char_copy(dest, parts[i].p, parts[i].len);
  1488. dest += parts[i].len;
  1489. }
  1490. *dest = '\0';
  1491. newPath.m_len = static_cast<size_type>(dest - newPath.c_str());
  1492. }
  1493. // Now we determine whether to leave a trailing separator or
  1494. // not and, if so, what type it should be.
  1495. WINSTL_ASSERT(m_len > 0);
  1496. char_type last = m_buffer[m_len - 1];
  1497. if( !bRemoveTrailingPathNameSeparator &&
  1498. traits_type::is_path_name_separator(last))
  1499. {
  1500. newPath.push_sep_(last);
  1501. }
  1502. else
  1503. {
  1504. newPath.pop_sep();
  1505. }
  1506. swap(newPath);
  1507. return *this;
  1508. }
  1509. template< ss_typename_param_k C
  1510. , ss_typename_param_k T
  1511. , ss_typename_param_k A
  1512. >
  1513. inline ss_typename_type_ret_k basic_path<C, T, A>::char_type const* basic_path<C, T, A>::get_file() const
  1514. {
  1515. char_type const* slash = last_slash_(m_buffer.data(), m_len);
  1516. if(NULL == slash)
  1517. {
  1518. slash = m_buffer.c_str();
  1519. }
  1520. else
  1521. {
  1522. ++slash;
  1523. }
  1524. return slash;
  1525. }
  1526. template< ss_typename_param_k C
  1527. , ss_typename_param_k T
  1528. , ss_typename_param_k A
  1529. >
  1530. inline ss_typename_type_ret_k basic_path<C, T, A>::char_type const* basic_path<C, T, A>::get_ext() const
  1531. {
  1532. char_type const *dot = traits_type::str_rchr(this->c_str(), '.');
  1533. char_type const *file = get_file();
  1534. static const char_type s_empty[1] = { '\0' };
  1535. if(NULL == dot)
  1536. {
  1537. return s_empty;
  1538. }
  1539. else if(dot < file)
  1540. {
  1541. return s_empty;
  1542. }
  1543. else
  1544. {
  1545. return dot + 1;
  1546. }
  1547. }
  1548. template< ss_typename_param_k C
  1549. , ss_typename_param_k T
  1550. , ss_typename_param_k A
  1551. >
  1552. inline ss_typename_type_ret_k basic_path<C, T, A>::size_type basic_path<C, T, A>::length() const
  1553. {
  1554. return m_len;
  1555. }
  1556. template< ss_typename_param_k C
  1557. , ss_typename_param_k T
  1558. , ss_typename_param_k A
  1559. >
  1560. inline ss_typename_type_ret_k basic_path<C, T, A>::size_type basic_path<C, T, A>::size() const
  1561. {
  1562. return length();
  1563. }
  1564. template< ss_typename_param_k C
  1565. , ss_typename_param_k T
  1566. , ss_typename_param_k A
  1567. >
  1568. inline ss_typename_type_ret_k basic_path<C, T, A>::size_type
  1569. /* static */ basic_path<C, T, A>::max_size()
  1570. {
  1571. return buffer_type_::max_size() - 1u;
  1572. }
  1573. template< ss_typename_param_k C
  1574. , ss_typename_param_k T
  1575. , ss_typename_param_k A
  1576. >
  1577. inline ss_typename_type_ret_k basic_path<C, T, A>::bool_type basic_path<C, T, A>::empty() const
  1578. {
  1579. return 0 == size();
  1580. }
  1581. template< ss_typename_param_k C
  1582. , ss_typename_param_k T
  1583. , ss_typename_param_k A
  1584. >
  1585. inline ss_typename_type_ret_k basic_path<C, T, A>::char_type const* basic_path<C, T, A>::c_str() const
  1586. {
  1587. return m_buffer.c_str();
  1588. }
  1589. template< ss_typename_param_k C
  1590. , ss_typename_param_k T
  1591. , ss_typename_param_k A
  1592. >
  1593. inline ss_typename_type_ret_k basic_path<C, T, A>::char_type const& basic_path<C, T, A>::operator [](ss_typename_type_k basic_path<C, T, A>::size_type index) const
  1594. {
  1595. WINSTL_MESSAGE_ASSERT("Index out of range", !(size() < index));
  1596. return c_str()[index];
  1597. }
  1598. template< ss_typename_param_k C
  1599. , ss_typename_param_k T
  1600. , ss_typename_param_k A
  1601. >
  1602. inline ws_bool_t basic_path<C, T, A>::exists() const
  1603. {
  1604. return traits_type::file_exists(this->c_str());
  1605. }
  1606. template< ss_typename_param_k C
  1607. , ss_typename_param_k T
  1608. , ss_typename_param_k A
  1609. >
  1610. inline ws_bool_t basic_path<C, T, A>::is_rooted() const
  1611. {
  1612. return traits_type::is_path_rooted(this->c_str());
  1613. }
  1614. template< ss_typename_param_k C
  1615. , ss_typename_param_k T
  1616. , ss_typename_param_k A
  1617. >
  1618. inline ws_bool_t basic_path<C, T, A>::is_absolute() const
  1619. {
  1620. return traits_type::is_path_absolute(this->c_str());
  1621. }
  1622. template< ss_typename_param_k C
  1623. , ss_typename_param_k T
  1624. , ss_typename_param_k A
  1625. >
  1626. inline ws_bool_t basic_path<C, T, A>::has_sep() const
  1627. {
  1628. return this->empty() ? false : traits_type::has_dir_end(this->c_str() + (this->size() - 1));
  1629. }
  1630. template< ss_typename_param_k C
  1631. , ss_typename_param_k T
  1632. , ss_typename_param_k A
  1633. >
  1634. inline ss_typename_type_ret_k basic_path<C, T, A>::size_type basic_path<C, T, A>::copy(ss_typename_type_k basic_path<C, T, A>::char_type *buffer, ss_typename_type_k basic_path<C, T, A>::size_type cchBuffer) const
  1635. {
  1636. return stlsoft_ns_qual(copy_contents)(buffer, cchBuffer, m_buffer.data(), m_len);
  1637. }
  1638. template< ss_typename_param_k C
  1639. , ss_typename_param_k T
  1640. , ss_typename_param_k A
  1641. >
  1642. inline ws_bool_t basic_path<C, T, A>::equivalent(basic_path<C, T, A> const& rhs) const
  1643. {
  1644. return equivalent(rhs.c_str());
  1645. }
  1646. template< ss_typename_param_k C
  1647. , ss_typename_param_k T
  1648. , ss_typename_param_k A
  1649. >
  1650. inline ws_bool_t basic_path<C, T, A>::equivalent(ss_typename_type_k basic_path<C, T, A>::char_type const* rhs) const
  1651. {
  1652. class_type lhs_(*this);
  1653. class_type rhs_(rhs);
  1654. return lhs_.make_absolute(false).canonicalise(true) == rhs_.make_absolute(false).canonicalise(true);
  1655. }
  1656. template< ss_typename_param_k C
  1657. , ss_typename_param_k T
  1658. , ss_typename_param_k A
  1659. >
  1660. inline ws_bool_t basic_path<C, T, A>::equal(basic_path<C, T, A> const& rhs) const
  1661. {
  1662. return equal(rhs.c_str());
  1663. }
  1664. template< ss_typename_param_k C
  1665. , ss_typename_param_k T
  1666. , ss_typename_param_k A
  1667. >
  1668. inline ws_bool_t basic_path<C, T, A>::equal(ss_typename_type_k basic_path<C, T, A>::char_type const* rhs) const
  1669. {
  1670. return 0 == traits_type::str_compare_no_case(m_buffer.c_str(), stlsoft_ns_qual(c_str_ptr)(rhs));
  1671. }
  1672. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  1673. /* ////////////////////////////////////////////////////////////////////// */
  1674. #ifndef _WINSTL_NO_NAMESPACE
  1675. # if defined(_STLSOFT_NO_NAMESPACE) || \
  1676. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  1677. } // namespace winstl
  1678. # else
  1679. } // namespace winstl_project
  1680. } // namespace stlsoft
  1681. # endif /* _STLSOFT_NO_NAMESPACE */
  1682. #endif /* !_WINSTL_NO_NAMESPACE */
  1683. /* In the special case of Intel behaving as VC++ 7.0 or earlier on Win32, we
  1684. * illegally insert into the std namespace.
  1685. */
  1686. #if defined(STLSOFT_CF_std_NAMESPACE)
  1687. # if ( ( defined(STLSOFT_COMPILER_IS_INTEL) && \
  1688. defined(_MSC_VER))) && \
  1689. _MSC_VER < 1310
  1690. namespace std
  1691. {
  1692. template< ss_typename_param_k C
  1693. , ss_typename_param_k T
  1694. , ss_typename_param_k A
  1695. >
  1696. inline void swap(winstl_ns_qual(basic_path)<C, T, A>& lhs, winstl_ns_qual(basic_path)<C, T, A>& rhs)
  1697. {
  1698. lhs.swap(rhs);
  1699. }
  1700. } // namespace std
  1701. # endif /* INTEL && _MSC_VER < 1310 */
  1702. #endif /* STLSOFT_CF_std_NAMESPACE */
  1703. /* /////////////////////////////////////////////////////////////////////////
  1704. * Namespace
  1705. *
  1706. * The string access shims exist either in the stlsoft namespace, or in the
  1707. * global namespace. This is required by the lookup rules.
  1708. *
  1709. */
  1710. #ifndef _WINSTL_NO_NAMESPACE
  1711. # if !defined(_STLSOFT_NO_NAMESPACE) && \
  1712. !defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  1713. namespace stlsoft
  1714. {
  1715. # else /* ? _STLSOFT_NO_NAMESPACE */
  1716. /* There is no stlsoft namespace, so must define in the global namespace */
  1717. # endif /* !_STLSOFT_NO_NAMESPACE */
  1718. using ::winstl::c_str_data;
  1719. using ::winstl::c_str_data_a;
  1720. using ::winstl::c_str_data_w;
  1721. using ::winstl::c_str_len;
  1722. using ::winstl::c_str_len_a;
  1723. using ::winstl::c_str_len_w;
  1724. using ::winstl::c_str_ptr;
  1725. using ::winstl::c_str_ptr_a;
  1726. using ::winstl::c_str_ptr_w;
  1727. using ::winstl::c_str_ptr_null;
  1728. using ::winstl::c_str_ptr_null_a;
  1729. using ::winstl::c_str_ptr_null_w;
  1730. # if !defined(_STLSOFT_NO_NAMESPACE) && \
  1731. !defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  1732. } // namespace stlsoft
  1733. # else /* ? _STLSOFT_NO_NAMESPACE */
  1734. /* There is no stlsoft namespace, so must define in the global namespace */
  1735. # endif /* !_STLSOFT_NO_NAMESPACE */
  1736. #endif /* !_WINSTL_NO_NAMESPACE */
  1737. /* ////////////////////////////////////////////////////////////////////// */
  1738. #endif /* WINSTL_INCL_WINSTL_FILESYSTEM_HPP_PATH */
  1739. /* ///////////////////////////// end of file //////////////////////////// */