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.

1697 lines
51 KiB

  1. /* /////////////////////////////////////////////////////////////////////////
  2. * File: unixstl/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 unixstl/filesystem/path.hpp
  43. *
  44. * \brief [C++ only] Definition of the unixstl::basic_path class template
  45. * (\ref group__library__filesystem "File System" Library).
  46. */
  47. #ifndef UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_PATH
  48. #define UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_PATH
  49. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  50. # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_PATH_MAJOR 6
  51. # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_PATH_MINOR 6
  52. # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_PATH_REVISION 4
  53. # define UNIXSTL_VER_UNIXSTL_FILESYSTEM_HPP_PATH_EDIT 236
  54. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  55. /* /////////////////////////////////////////////////////////////////////////
  56. * Includes
  57. */
  58. #ifndef UNIXSTL_INCL_UNIXSTL_H_UNIXSTL
  59. # include <unixstl/unixstl.h>
  60. #endif /* !UNIXSTL_INCL_UNIXSTL_H_UNIXSTL */
  61. #ifndef UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS
  62. # include <unixstl/filesystem/filesystem_traits.hpp>
  63. #endif /* !UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_FILESYSTEM_TRAITS */
  64. #ifndef UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_FILE_PATH_BUFFER
  65. # include <unixstl/filesystem/file_path_buffer.hpp>
  66. #endif /* !UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_FILE_PATH_BUFFER */
  67. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  68. # ifndef UNIXSTL_INCL_UNIXSTL_ERROR_HPP_WINDOWS_EXCEPTIONS
  69. # include <unixstl/error/exceptions.hpp>
  70. # endif /* !UNIXSTL_INCL_UNIXSTL_ERROR_HPP_WINDOWS_EXCEPTIONS */
  71. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  72. #ifndef STLSOFT_INCL_STLSOFT_MEMORY_HPP_ALLOCATOR_BASE
  73. # include <stlsoft/memory/allocator_base.hpp> // for STLSOFT_LF_ALLOCATOR_REBIND_SUPPORT
  74. #endif /* !STLSOFT_INCL_STLSOFT_MEMORY_HPP_ALLOCATOR_BASE */
  75. #ifndef STLSOFT_INCL_STLSOFT_MEMORY_HPP_ALLOCATOR_SELECTOR
  76. # include <stlsoft/memory/allocator_selector.hpp>
  77. #endif /* !STLSOFT_INCL_STLSOFT_MEMORY_HPP_ALLOCATOR_SELECTOR */
  78. #ifndef STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_HPP_STRING
  79. # include <stlsoft/shims/access/string.hpp>
  80. #endif /* !STLSOFT_INCL_STLSOFT_SHIMS_ACCESS_HPP_STRING */
  81. #ifndef UNIXSTL_INCL_UNIXSTL_SHIMS_ACCESS_HPP_STRING
  82. # include <unixstl/shims/access/string.hpp>
  83. #endif /* !UNIXSTL_INCL_UNIXSTL_SHIMS_ACCESS_HPP_STRING */
  84. #ifndef STLSOFT_INCL_STLSOFT_MEMORY_HPP_AUTO_BUFFER
  85. # include <stlsoft/memory/auto_buffer.hpp>
  86. #endif /* !STLSOFT_INCL_STLSOFT_MEMORY_HPP_AUTO_BUFFER */
  87. #ifndef STLSOFT_INCL_STLSOFT_STRING_HPP_COPY_FUNCTIONS
  88. # include <stlsoft/string/copy_functions.hpp>
  89. #endif /* !STLSOFT_INCL_STLSOFT_STRING_HPP_COPY_FUNCTIONS */
  90. #ifndef STLSOFT_INCL_STLSOFT_UTIL_HPP_STD_SWAP
  91. # include <stlsoft/util/std_swap.hpp>
  92. #endif /* !STLSOFT_INCL_STLSOFT_UTIL_HPP_STD_SWAP */
  93. #ifndef STLSOFT_INCL_STDEXCEPT
  94. # define STLSOFT_INCL_STDEXCEPT
  95. # include <stdexcept> // for std::logic_error
  96. #endif /* !STLSOFT_INCL_STDEXCEPT */
  97. #ifdef _WIN32
  98. # include <ctype.h>
  99. #endif /* _WIN32 */
  100. /* /////////////////////////////////////////////////////////////////////////
  101. * Namespace
  102. */
  103. #ifndef _UNIXSTL_NO_NAMESPACE
  104. # if defined(_STLSOFT_NO_NAMESPACE) || \
  105. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  106. /* There is no stlsoft namespace, so must define ::unixstl */
  107. namespace unixstl
  108. {
  109. # else
  110. /* Define stlsoft::unixstl_project */
  111. namespace stlsoft
  112. {
  113. namespace unixstl_project
  114. {
  115. # endif /* _STLSOFT_NO_NAMESPACE */
  116. #endif /* !_UNIXSTL_NO_NAMESPACE */
  117. /* /////////////////////////////////////////////////////////////////////////
  118. * basic_path
  119. *
  120. * This class represents a path, and effectively acts as a C-string of its value.
  121. */
  122. /** Represents a path
  123. *
  124. * \ingroup group__library__filesystem
  125. *
  126. * \param C The character type
  127. * \param T The traits type. Defaults to filesystem_traits<C>. On translators that do not support default template arguments, it must be explicitly stipulated
  128. * \param A The allocator class. Defaults to stlsoft::allocator_selector<C>::allocator_type. On translators that do not support default template arguments, it must be explicitly stipulated
  129. *
  130. * \note This class derives from the Synesis Software class Path, but has been influenced
  131. * by other, later, ideas. The idea of using the / operator for path concatenation was
  132. * sparked by the Boost implementation (although the details were not investigated prior
  133. * to this implementation, so the two may have significant semantic differences). This
  134. * has been added without requiring any major fundamental changes to the original
  135. * <code>push/pop</code>-based interface
  136. */
  137. template< ss_typename_param_k C
  138. #ifdef STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT
  139. , ss_typename_param_k T = filesystem_traits<C>
  140. , ss_typename_param_k A = ss_typename_type_def_k stlsoft_ns_qual(allocator_selector)<C>::allocator_type
  141. #else /* ? STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT */
  142. , ss_typename_param_k T /* = filesystem_traits<C> */
  143. , ss_typename_param_k A /* = ss_typename_type_def_k stlsoft_ns_qual(allocator_selector)<C>::allocator_type */
  144. #endif /* STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT */
  145. >
  146. class basic_path
  147. {
  148. /// \name Types
  149. /// @{
  150. public:
  151. /// The char type
  152. typedef C char_type;
  153. /// The traits type
  154. typedef T traits_type;
  155. /// The allocator type
  156. typedef A allocator_type;
  157. /// The current parameterisation of the type
  158. typedef basic_path<C, T, A> class_type;
  159. /// The size type
  160. typedef us_size_t size_type;
  161. /// The Boolean type
  162. typedef us_bool_t bool_type;
  163. // TODO: Use the slice string, and provide iterators over the directory parts
  164. /// @}
  165. /// \name Construction
  166. /// @{
  167. public:
  168. /// Constructs an empty path
  169. basic_path();
  170. /// Constructs a path from \c path
  171. ss_explicit_k basic_path(char_type const* path);
  172. #ifdef STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT
  173. /// Constructs a path from \c path
  174. template<ss_typename_param_k S>
  175. ss_explicit_k basic_path(S const& s)
  176. {
  177. m_len = stlsoft_ns_qual(c_str_len)(s);
  178. traits_type::char_copy(&m_buffer[0], stlsoft_ns_qual(c_str_data)(s), m_len);
  179. m_buffer[m_len] = '\0';
  180. }
  181. #endif /* STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT */
  182. /// Constructs a path from \c cch characters in \c path
  183. basic_path(char_type const* path, size_type cch);
  184. #ifndef STLSOFT_CF_NO_COPY_CTOR_AND_COPY_CTOR_TEMPLATE_OVERLOAD
  185. /// Copies the contents of \c rhs
  186. basic_path(class_type const& rhs);
  187. #endif /* !STLSOFT_CF_NO_COPY_CTOR_AND_COPY_CTOR_TEMPLATE_OVERLOAD */
  188. #ifndef STLSOFT_CF_NO_COPY_CTOR_AND_COPY_CTOR_TEMPLATE_OVERLOAD
  189. /// Copies the contents of \c rhs
  190. class_type& operator =(class_type const& rhs);
  191. #endif /* !STLSOFT_CF_NO_COPY_CTOR_AND_COPY_CTOR_TEMPLATE_OVERLOAD */
  192. /// Copies the contents of \c rhs
  193. class_type& operator =(char_type const* rhs);
  194. #ifdef STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT
  195. /// Copies the contents of \c s
  196. template<ss_typename_param_k S>
  197. class_type& operator =(S const& s)
  198. {
  199. return operator_equal_(stlsoft_ns_qual(c_str_ptr)(s));
  200. }
  201. #endif /* STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT */
  202. // Creates a root path
  203. static class_type root(char_type const* s);
  204. #ifdef STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT
  205. // Creates a root path
  206. template<ss_typename_param_k S>
  207. static class_type root(S const& s)
  208. {
  209. return root(stlsoft_ns_qual(c_str_ptr)(s));
  210. }
  211. #endif /* STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT */
  212. /// @}
  213. /// \name Operations
  214. /// @{
  215. public:
  216. /// Appends the contents of \c rhs to the path
  217. class_type& push(class_type const& rhs, bool_type bAddPathNameSeparator = false);
  218. /// Appends the contents of \c rhs to the path
  219. class_type& push(char_type const* rhs, bool_type bAddPathNameSeparator = false);
  220. /// Appends the contents of \c rhs to the path as an extension
  221. class_type& push_ext(class_type const& rhs, bool_type bAddPathNameSeparator = false);
  222. /// Appends the contents of \c rhs to the path as an extension
  223. class_type& push_ext(char_type const* rhs, bool_type bAddPathNameSeparator = false);
  224. /// Ensures that the path has a trailing path name separator
  225. class_type& push_sep();
  226. /// Pops the last path element from the path
  227. ///
  228. /// \note In previous versions, this operation did not remove the
  229. /// left-most path component. That behaviour is no longer supported,
  230. /// and the method will now leave the path instance empty in that
  231. /// case.
  232. class_type& pop(bool_type bRemoveTrailingPathNameSeparator = true);
  233. /// Ensures that the path does not have a trailing path name separator
  234. ///
  235. /// \note Does not trim the separator character from the root designator
  236. class_type& pop_sep();
  237. /// Removes the extension, if any, from the file component of the path
  238. class_type& pop_ext();
  239. /// Equivalent to push()
  240. class_type& operator /=(char_type const* rhs);
  241. #if !defined(STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT) || \
  242. defined(STLSOFT_CF_MEMBER_TEMPLATE_OVERLOAD_DISCRIMINATED)
  243. /// Equivalent to push()
  244. class_type& operator /=(class_type const& rhs);
  245. #endif /* !STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT || STLSOFT_CF_MEMBER_TEMPLATE_OVERLOAD_DISCRIMINATED */
  246. #if defined(STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT)
  247. /// Equivalent to push()
  248. template <ss_typename_param_k S>
  249. class_type& operator /=(S const& rhs)
  250. {
  251. return push(stlsoft_ns_qual(c_str_ptr)(rhs));
  252. }
  253. #endif /* STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT */
  254. /// Removes all content
  255. void clear();
  256. /// Converts the path to absolute form
  257. class_type& make_absolute(bool_type bRemoveTrailingPathNameSeparator = true);
  258. /// Canonicalises the path, removing all "./" parts and evaluating all "../" parts
  259. class_type& canonicalise(bool_type bRemoveTrailingPathNameSeparator = true);
  260. /// @}
  261. /// \name Attributes
  262. /// @{
  263. public:
  264. /// Returns a pointer to the part of the path after the last path name separator
  265. ///
  266. /// \note If the path represents a directory, the name of the directory will be returned, except
  267. /// if the path is terminated by the path name separator
  268. ///
  269. /// \note If the path contains no path name separator, the full path will be returned
  270. char_type const* get_file() const;
  271. /// Returns a pointer to the extension, or to the empty string if there is no extension
  272. char_type const* get_ext() const;
  273. /// Returns the length of the converted path
  274. size_type length() const;
  275. /// Returns the length of the converted path
  276. ///
  277. /// \remarks Equivalent to length()
  278. size_type size() const;
  279. /// The maximum possible length of a path
  280. static size_type max_size();
  281. /// Determines whether the path is empty
  282. bool_type empty() const;
  283. /// Conversion to a non-mutable (const) pointer to the path
  284. char_type const* c_str() const;
  285. /// Returns a non-mutable (const) reference to the character at
  286. /// the given index
  287. ///
  288. /// \note The behaviour is undefined if <code>index >= size()</code>.
  289. char_type const& operator [](size_type index) const;
  290. /// Indicates whether the path represents an existing file system entry
  291. bool_type exists() const;
  292. /// Indicates whether the path is rooted
  293. bool_type is_rooted() const;
  294. /// Indicates whether the path is absolute
  295. bool_type is_absolute() const;
  296. /// Indicates whether the path has a trailing separator
  297. bool_type has_sep() const;
  298. /// Copies the contents into a caller supplied buffer
  299. ///
  300. /// \param buffer Pointer to character buffer to receive the contents.
  301. /// May be NULL, in which case the method returns size().
  302. /// \param cchBuffer Number of characters of available space in \c buffer.
  303. size_type copy(char_type *buffer, size_type cchBuffer) const;
  304. /// @}
  305. /// \name Comparison
  306. /// @{
  307. public:
  308. bool_type equivalent(char_type const* rhs) const;
  309. bool_type equivalent(class_type const& rhs) const;
  310. bool_type equal(char_type const* rhs) const;
  311. bool_type equal(class_type const& rhs) const;
  312. /// @}
  313. /// \name Iteration
  314. /// @{
  315. public:
  316. #if 0
  317. directory_iterator dir_begin() const;
  318. directory_iterator dir_end() const;
  319. #endif /* 0 */
  320. /// @}
  321. // Implementation
  322. private:
  323. class_type& operator_equal_(char_type const* path);
  324. void swap(class_type& rhs);
  325. class_type& concat_(char_type const* rhs, size_type cch);
  326. static char_type const *next_slash_or_end(char_type const* p);
  327. static char_type path_name_separator_alt();
  328. // Members
  329. private:
  330. typedef basic_file_path_buffer<
  331. char_type
  332. , allocator_type
  333. > buffer_type_;
  334. struct part
  335. {
  336. enum Type
  337. {
  338. normal
  339. , dot
  340. , dotdot
  341. };
  342. size_type len;
  343. char_type const* p;
  344. Type type;
  345. };
  346. buffer_type_ m_buffer;
  347. size_type m_len;
  348. };
  349. /* /////////////////////////////////////////////////////////////////////////
  350. * Typedefs for commonly encountered types
  351. */
  352. /** Specialisation of the basic_path template for the ANSI character type \c char
  353. *
  354. * \ingroup group__library__filesystem
  355. */
  356. typedef basic_path<us_char_a_t, filesystem_traits<us_char_a_t> > path_a;
  357. /** Specialisation of the basic_path template for the Unicode character type \c wchar_t
  358. *
  359. * \ingroup group__library__filesystem
  360. */
  361. typedef basic_path<us_char_w_t, filesystem_traits<us_char_w_t> > path_w;
  362. /** Specialisation of the basic_path template for the ANSI character type \c char
  363. *
  364. * \ingroup group__library__filesystem
  365. */
  366. typedef basic_path<us_char_a_t, filesystem_traits<us_char_a_t> > path;
  367. /* /////////////////////////////////////////////////////////////////////////
  368. * Support for PlatformSTL redefinition by inheritance+namespace, for confused
  369. * compilers (e.g. VC++ 6)
  370. */
  371. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  372. template< ss_typename_param_k C
  373. # ifdef STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT
  374. , ss_typename_param_k T = filesystem_traits<C>
  375. , ss_typename_param_k A = ss_typename_type_def_k stlsoft_ns_qual(allocator_selector)<C>::allocator_type
  376. # else /* ? STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT */
  377. , ss_typename_param_k T /* = filesystem_traits<C> */
  378. , ss_typename_param_k A /* = ss_typename_type_def_k stlsoft_ns_qual(allocator_selector)<C>::allocator_type */
  379. # endif /* STLSOFT_CF_TEMPLATE_CLASS_DEFAULT_CLASS_ARGUMENT_SUPPORT */
  380. >
  381. class basic_path__
  382. : public unixstl_ns_qual(basic_path)<C, T, A>
  383. {
  384. private:
  385. typedef unixstl_ns_qual(basic_path)<C, T, A> parent_class_type;
  386. typedef unixstl_ns_qual(basic_path__)<C, T, A> class_type;
  387. public:
  388. typedef ss_typename_type_k parent_class_type::char_type char_type;
  389. typedef ss_typename_type_k parent_class_type::traits_type traits_type;
  390. typedef ss_typename_type_k parent_class_type::allocator_type allocator_type;
  391. typedef ss_typename_type_k parent_class_type::size_type size_type;
  392. public:
  393. basic_path__()
  394. : parent_class_type()
  395. {}
  396. ss_explicit_k basic_path__(char_type const* path)
  397. : parent_class_type(path)
  398. {}
  399. # ifdef STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT
  400. /// Constructs a path from \c path
  401. template<ss_typename_param_k S>
  402. ss_explicit_k basic_path__(S const& s)
  403. : parent_class_type(s)
  404. {}
  405. # endif /* STLSOFT_CF_MEMBER_TEMPLATE_CTOR_SUPPORT */
  406. basic_path__(char_type const* path, size_type cch)
  407. : parent_class_type(path, cch)
  408. {}
  409. basic_path__(class_type const& rhs)
  410. : parent_class_type(rhs)
  411. {}
  412. class_type& operator =(class_type const& rhs)
  413. {
  414. parent_class_type::operator =(rhs);
  415. return *this;
  416. }
  417. class_type& operator =(char_type const* rhs)
  418. {
  419. parent_class_type::operator =(rhs);
  420. return *this;
  421. }
  422. # ifdef STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT
  423. template<ss_typename_param_k S>
  424. class_type& operator =(S const& s)
  425. {
  426. parent_class_type::operator =(s);
  427. return *this;
  428. }
  429. # endif /* STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT */
  430. };
  431. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  432. /* /////////////////////////////////////////////////////////////////////////
  433. * Operators
  434. */
  435. template< ss_typename_param_k C
  436. , ss_typename_param_k T
  437. , ss_typename_param_k A
  438. >
  439. inline us_bool_t operator ==(basic_path<C, T, A> const& lhs, ss_typename_type_k basic_path<C, T, A>::char_type const* rhs)
  440. {
  441. return lhs.equal(rhs);
  442. }
  443. template< ss_typename_param_k C
  444. , ss_typename_param_k T
  445. , ss_typename_param_k A
  446. >
  447. inline us_bool_t operator !=(basic_path<C, T, A> const& lhs, ss_typename_type_k basic_path<C, T, A>::char_type const* rhs)
  448. {
  449. return !lhs.equal(rhs);
  450. }
  451. template< ss_typename_param_k C
  452. , ss_typename_param_k T
  453. , ss_typename_param_k A
  454. >
  455. inline us_bool_t operator ==(ss_typename_type_k basic_path<C, T, A>::char_type const* lhs, basic_path<C, T, A> const& rhs)
  456. {
  457. return rhs.equal(lhs);
  458. }
  459. template< ss_typename_param_k C
  460. , ss_typename_param_k T
  461. , ss_typename_param_k A
  462. >
  463. inline us_bool_t operator !=(ss_typename_type_k basic_path<C, T, A>::char_type const* lhs, basic_path<C, T, A> const& rhs)
  464. {
  465. return !rhs.equal(lhs);
  466. }
  467. template< ss_typename_param_k C
  468. , ss_typename_param_k T
  469. , ss_typename_param_k A
  470. >
  471. inline us_bool_t operator ==(basic_path<C, T, A> const& lhs, basic_path<C, T, A> const& rhs)
  472. {
  473. return lhs.equal(rhs);
  474. }
  475. template< ss_typename_param_k C
  476. , ss_typename_param_k T
  477. , ss_typename_param_k A
  478. >
  479. inline us_bool_t operator !=(basic_path<C, T, A> const& lhs, basic_path<C, T, A> const& rhs)
  480. {
  481. return !lhs.equal(rhs);
  482. }
  483. // operator /
  484. /** Concatenates \c rhs to the path \c lhs
  485. *
  486. * \ingroup group__library__filesystem
  487. */
  488. template< ss_typename_param_k C
  489. , ss_typename_param_k T
  490. , ss_typename_param_k A
  491. >
  492. 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)
  493. {
  494. return basic_path<C, T, A>(lhs) /= rhs;
  495. }
  496. /** Concatenates \c rhs to the path \c lhs
  497. *
  498. * \ingroup group__library__filesystem
  499. */
  500. template< ss_typename_param_k C
  501. , ss_typename_param_k T
  502. , ss_typename_param_k A
  503. >
  504. 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)
  505. {
  506. return basic_path<C, T, A>(lhs) /= rhs;
  507. }
  508. /** Concatenates \c rhs to the path \c lhs
  509. *
  510. * \ingroup group__library__filesystem
  511. */
  512. template< ss_typename_param_k C
  513. , ss_typename_param_k T
  514. , ss_typename_param_k A
  515. >
  516. inline basic_path<C, T, A> operator /(basic_path<C, T, A> const& lhs, basic_path<C, T, A> const& rhs)
  517. {
  518. return basic_path<C, T, A>(lhs) /= rhs;
  519. }
  520. /* /////////////////////////////////////////////////////////////////////////
  521. * Helper functions
  522. */
  523. #if !defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  524. # if !defined(STLSOFT_COMPILER_IS_MSVC) || \
  525. _MSC_VER >= 1100
  526. /** This helper function makes a path variable without needing to
  527. * qualify the template parameter.
  528. *
  529. * \ingroup group__library__filesystem
  530. */
  531. template<ss_typename_param_k C>
  532. inline basic_path<C> make_path(C const* path)
  533. {
  534. return basic_path<C>(path);
  535. }
  536. # endif /* compiler */
  537. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  538. /* /////////////////////////////////////////////////////////////////////////
  539. * swapping
  540. */
  541. template< ss_typename_param_k C
  542. , ss_typename_param_k T
  543. , ss_typename_param_k A
  544. >
  545. inline void swap(basic_path<C, T, A>& lhs, basic_path<C, T, A>& rhs)
  546. {
  547. lhs.swap(rhs);
  548. }
  549. /* /////////////////////////////////////////////////////////////////////////
  550. * Shims
  551. */
  552. /** \ref group__concept__shim__string_access__c_str_data for unixstl::basic_path
  553. *
  554. * \ingroup group__concept__shim__string_access
  555. */
  556. template< ss_typename_param_k C
  557. , ss_typename_param_k T
  558. , ss_typename_param_k A
  559. >
  560. inline C const* c_str_data(unixstl_ns_qual(basic_path)<C, T, A> const& b)
  561. {
  562. return b.c_str();
  563. }
  564. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  565. template <ss_typename_param_k T, ss_typename_param_k A>
  566. inline us_char_a_t const* c_str_data_a(unixstl_ns_qual(basic_path)<us_char_a_t, T, A> const& b)
  567. {
  568. return b.c_str();
  569. }
  570. template <ss_typename_param_k T, ss_typename_param_k A>
  571. inline us_char_w_t const* c_str_data_w(unixstl_ns_qual(basic_path)<us_char_w_t, T, A> const& b)
  572. {
  573. return b.c_str();
  574. }
  575. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  576. /** \ref group__concept__shim__string_access__c_str_len for unixstl::basic_path
  577. *
  578. * \ingroup group__concept__shim__string_access
  579. */
  580. template< ss_typename_param_k C
  581. , ss_typename_param_k T
  582. , ss_typename_param_k A
  583. >
  584. inline us_size_t c_str_len(unixstl_ns_qual(basic_path)<C, T, A> const& b)
  585. {
  586. return stlsoft_ns_qual(c_str_len)(b.c_str());
  587. }
  588. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  589. template <ss_typename_param_k T, ss_typename_param_k A>
  590. inline us_size_t c_str_len_a(unixstl_ns_qual(basic_path)<us_char_a_t, T, A> const& b)
  591. {
  592. return stlsoft_ns_qual(c_str_len_a)(b.c_str());
  593. }
  594. template <ss_typename_param_k T, ss_typename_param_k A>
  595. inline us_size_t c_str_len_w(unixstl_ns_qual(basic_path)<us_char_w_t, T, A> const& b)
  596. {
  597. return stlsoft_ns_qual(c_str_len_w)(b.c_str());
  598. }
  599. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  600. /** \ref group__concept__shim__string_access__c_str_ptr for unixstl::basic_path
  601. *
  602. * \ingroup group__concept__shim__string_access
  603. */
  604. template< ss_typename_param_k C
  605. , ss_typename_param_k T
  606. , ss_typename_param_k A
  607. >
  608. inline C const* c_str_ptr(unixstl_ns_qual(basic_path)<C, T, A> const& b)
  609. {
  610. return b.c_str();
  611. }
  612. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  613. template <ss_typename_param_k T, ss_typename_param_k A>
  614. inline us_char_a_t const* c_str_ptr_a(unixstl_ns_qual(basic_path)<us_char_a_t, T, A> const& b)
  615. {
  616. return b.c_str();
  617. }
  618. template <ss_typename_param_k T, ss_typename_param_k A>
  619. inline us_char_w_t const* c_str_ptr_w(unixstl_ns_qual(basic_path)<us_char_w_t, T, A> const& b)
  620. {
  621. return b.c_str();
  622. }
  623. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  624. /** \ref group__concept__shim__string_access__c_str_ptr_null for unixstl::basic_path
  625. *
  626. * \ingroup group__concept__shim__string_access
  627. */
  628. template< ss_typename_param_k C
  629. , ss_typename_param_k T
  630. , ss_typename_param_k A
  631. >
  632. inline C const* c_str_ptr_null(unixstl_ns_qual(basic_path)<C, T, A> const& b)
  633. {
  634. return stlsoft_ns_qual(c_str_ptr_null)(b.c_str());
  635. }
  636. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  637. template <ss_typename_param_k T, ss_typename_param_k A>
  638. inline us_char_a_t const* c_str_ptr_null_a(unixstl_ns_qual(basic_path)<us_char_a_t, T, A> const& b)
  639. {
  640. return stlsoft_ns_qual(c_str_ptr_null_a)(b.c_str());
  641. }
  642. template <ss_typename_param_k T, ss_typename_param_k A>
  643. inline us_char_w_t const* c_str_ptr_null_w(unixstl_ns_qual(basic_path)<us_char_w_t, T, A> const& b)
  644. {
  645. return stlsoft_ns_qual(c_str_ptr_null_w)(b.c_str());
  646. }
  647. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  648. /** \ref group__concept__shim__stream_insertion "stream insertion shim" for unixstl::basic_path
  649. *
  650. * \ingroup group__concept__shim__stream_insertion
  651. */
  652. template< ss_typename_param_k S
  653. , ss_typename_param_k C
  654. , ss_typename_param_k T
  655. , ss_typename_param_k A
  656. >
  657. inline S& operator <<(S& s, unixstl_ns_qual(basic_path)<C, T, A> const& b)
  658. {
  659. s << b.c_str();
  660. return s;
  661. }
  662. ////////////////////////////////////////////////////////////////////////////
  663. // Unit-testing
  664. #ifdef STLSOFT_UNITTEST
  665. # include "./unittest/path_unittest_.h"
  666. #endif /* STLSOFT_UNITTEST */
  667. ////////////////////////////////////////////////////////////////////////////
  668. // Implementation
  669. #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION
  670. # if defined(STLSOFT_COMPILER_IS_MSVC) && \
  671. _MSC_VER >= 1300
  672. # pragma warning(push)
  673. # pragma warning(disable : 4702)
  674. # endif /* compiler*/
  675. template< ss_typename_param_k C
  676. , ss_typename_param_k T
  677. , ss_typename_param_k A
  678. >
  679. 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)
  680. {
  681. for(; ; ++p)
  682. {
  683. switch(*p)
  684. {
  685. case '/':
  686. #ifdef _WIN32
  687. case '\\':
  688. #endif /* _WIN32 */
  689. ++p;
  690. case '\0':
  691. return p;
  692. default:
  693. break;
  694. }
  695. }
  696. return NULL;
  697. }
  698. # if defined(STLSOFT_COMPILER_IS_MSVC) && \
  699. _MSC_VER >= 1300
  700. # pragma warning(pop)
  701. # endif /* compiler*/
  702. template< ss_typename_param_k C
  703. , ss_typename_param_k T
  704. , ss_typename_param_k A
  705. >
  706. inline /* static */ ss_typename_param_k basic_path<C, T, A>::char_type basic_path<C, T, A>::path_name_separator_alt()
  707. {
  708. return '\\';
  709. }
  710. template< ss_typename_param_k C
  711. , ss_typename_param_k T
  712. , ss_typename_param_k A
  713. >
  714. inline void basic_path<C, T, A>::swap(basic_path<C, T, A>& rhs)
  715. {
  716. m_buffer.swap(rhs.m_buffer);
  717. std_swap(m_len, rhs.m_len);
  718. }
  719. template< ss_typename_param_k C
  720. , ss_typename_param_k T
  721. , ss_typename_param_k A
  722. >
  723. inline
  724. ss_typename_param_k basic_path<C, T, A>::class_type&
  725. basic_path<C, T, A>::concat_(
  726. ss_typename_param_k basic_path<C, T, A>::char_type const* rhs
  727. , ss_typename_param_k basic_path<C, T, A>::size_type cch
  728. )
  729. {
  730. traits_type::char_copy(&m_buffer[0] + m_len, rhs, cch);
  731. m_len += cch;
  732. m_buffer[m_len] = '\0';
  733. return *this;
  734. }
  735. template< ss_typename_param_k C
  736. , ss_typename_param_k T
  737. , ss_typename_param_k A
  738. >
  739. inline basic_path<C, T, A>::basic_path()
  740. : m_len(0)
  741. {
  742. m_buffer[0] = '\0';
  743. }
  744. template< ss_typename_param_k C
  745. , ss_typename_param_k T
  746. , ss_typename_param_k A
  747. >
  748. inline /* ss_explicit_k */ basic_path<C, T, A>::basic_path(ss_typename_type_k basic_path<C, T, A>::char_type const* path)
  749. : m_len(0)
  750. {
  751. if(NULL != path)
  752. {
  753. size_type cch = traits_type::str_len(path);
  754. UNIXSTL_MESSAGE_ASSERT("path too long", cch < m_buffer.size());
  755. traits_type::char_copy(&m_buffer[0], path, cch);
  756. m_len = cch;
  757. }
  758. m_buffer[m_len] = '\0';
  759. }
  760. template< ss_typename_param_k C
  761. , ss_typename_param_k T
  762. , ss_typename_param_k A
  763. >
  764. inline basic_path<C, T, A>::basic_path( ss_typename_type_k basic_path<C, T, A>::char_type const* path
  765. , ss_typename_type_k basic_path<C, T, A>::size_type cch)
  766. : m_len(cch)
  767. {
  768. UNIXSTL_ASSERT((NULL != path) || (0 == cch));
  769. if(0 != cch)
  770. {
  771. UNIXSTL_MESSAGE_ASSERT("path too long", cch < m_buffer.size());
  772. traits_type::char_copy(&m_buffer[0], path, cch);
  773. }
  774. m_buffer[cch] = '\0';
  775. }
  776. #ifndef STLSOFT_CF_NO_COPY_CTOR_AND_COPY_CTOR_TEMPLATE_OVERLOAD
  777. template< ss_typename_param_k C
  778. , ss_typename_param_k T
  779. , ss_typename_param_k A
  780. >
  781. inline basic_path<C, T, A>::basic_path(basic_path<C, T, A> const& rhs)
  782. : m_len(rhs.m_len)
  783. {
  784. traits_type::char_copy(&m_buffer[0], rhs.m_buffer.c_str(), rhs.m_len + 1); // +1 to get the NUL terminator
  785. }
  786. #endif /* !STLSOFT_CF_NO_COPY_CTOR_AND_COPY_CTOR_TEMPLATE_OVERLOAD */
  787. #ifndef STLSOFT_CF_NO_COPY_CTOR_AND_COPY_CTOR_TEMPLATE_OVERLOAD
  788. template< ss_typename_param_k C
  789. , ss_typename_param_k T
  790. , ss_typename_param_k A
  791. >
  792. inline basic_path<C, T, A>& basic_path<C, T, A>::operator =(basic_path<C, T, A> const& path)
  793. {
  794. class_type newPath(path);
  795. swap(newPath);
  796. return *this;
  797. }
  798. #endif /* !STLSOFT_CF_NO_COPY_CTOR_AND_COPY_CTOR_TEMPLATE_OVERLOAD */
  799. template< ss_typename_param_k C
  800. , ss_typename_param_k T
  801. , ss_typename_param_k A
  802. >
  803. 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)
  804. {
  805. return operator_equal_(path);
  806. }
  807. template< ss_typename_param_k C
  808. , ss_typename_param_k T
  809. , ss_typename_param_k A
  810. >
  811. 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)
  812. {
  813. class_type newPath(path);
  814. swap(newPath);
  815. return *this;
  816. }
  817. template< ss_typename_param_k C
  818. , ss_typename_param_k T
  819. , ss_typename_param_k A
  820. >
  821. 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)
  822. {
  823. return class_type(s);
  824. }
  825. template< ss_typename_param_k C
  826. , ss_typename_param_k T
  827. , ss_typename_param_k A
  828. >
  829. inline basic_path<C, T, A>& basic_path<C, T, A>::push(class_type const& rhs, us_bool_t bAddPathNameSeparator /* = false */)
  830. {
  831. return push(rhs.c_str(), bAddPathNameSeparator);
  832. }
  833. template< ss_typename_param_k C
  834. , ss_typename_param_k T
  835. , ss_typename_param_k A
  836. >
  837. inline basic_path<C, T, A>& basic_path<C, T, A>::push(char_type const* rhs, us_bool_t bAddPathNameSeparator /* = false */)
  838. {
  839. UNIXSTL_ASSERT(NULL != rhs);
  840. if('\0' != *rhs)
  841. {
  842. if(traits_type::is_path_rooted(rhs))
  843. {
  844. class_type newPath(rhs);
  845. swap(newPath);
  846. }
  847. else
  848. {
  849. class_type newPath(*this);
  850. newPath.push_sep();
  851. newPath.concat_(rhs, traits_type::str_len(rhs));
  852. if(bAddPathNameSeparator)
  853. {
  854. newPath.push_sep();
  855. }
  856. swap(newPath);
  857. }
  858. }
  859. return *this;
  860. }
  861. #if 0
  862. template< ss_typename_param_k C
  863. , ss_typename_param_k T
  864. , ss_typename_param_k A
  865. >
  866. inline basic_path<C, T, A>& basic_path<C, T, A>::push_ext(class_type const& rhs, us_bool_t bAddPathNameSeparator /* = false */)
  867. {
  868. }
  869. #endif /* 0 */
  870. template< ss_typename_param_k C
  871. , ss_typename_param_k T
  872. , ss_typename_param_k A
  873. >
  874. inline basic_path<C, T, A>& basic_path<C, T, A>::push_ext(char_type const* rhs, us_bool_t bAddPathNameSeparator /* = false */)
  875. {
  876. UNIXSTL_ASSERT(NULL != rhs);
  877. class_type newPath(*this);
  878. newPath.pop_sep();
  879. if('.' != *rhs)
  880. {
  881. static char_type const s_dot[] = { '.', '\0' };
  882. newPath.concat_(&s_dot[0], 1u);
  883. }
  884. newPath.concat_(rhs, traits_type::str_len(rhs));
  885. if(bAddPathNameSeparator)
  886. {
  887. newPath.push_sep();
  888. }
  889. swap(newPath);
  890. return *this;
  891. }
  892. template< ss_typename_param_k C
  893. , ss_typename_param_k T
  894. , ss_typename_param_k A
  895. >
  896. inline basic_path<C, T, A>& basic_path<C, T, A>::push_sep()
  897. {
  898. if(0 != m_len)
  899. {
  900. if(traits_type::path_name_separator() != m_buffer[m_len - 1])
  901. {
  902. #ifdef _WIN32
  903. if(path_name_separator_alt() != m_buffer[m_len - 1])
  904. #endif /* _WIN32 */
  905. {
  906. UNIXSTL_ASSERT(m_len + 1 < m_buffer.size());
  907. m_buffer[m_len] = traits_type::path_name_separator();
  908. m_buffer[m_len + 1] = '\0';
  909. ++m_len;
  910. }
  911. }
  912. }
  913. return *this;
  914. }
  915. template< ss_typename_param_k C
  916. , ss_typename_param_k T
  917. , ss_typename_param_k A
  918. >
  919. inline basic_path<C, T, A>& basic_path<C, T, A>::pop(us_bool_t bRemoveTrailingPathNameSeparator /* = true */)
  920. {
  921. char_type *slash = traits_type::str_rchr(m_buffer.c_str(), traits_type::path_name_separator());
  922. #ifdef _WIN32
  923. char_type *slash_a = traits_type::str_rchr(m_buffer.c_str(), path_name_separator_alt());
  924. if(slash_a > slash)
  925. {
  926. slash = slash_a;
  927. }
  928. #endif /* _WIN32 */
  929. if(NULL != slash)
  930. {
  931. *(slash + 1) = '\0';
  932. m_len = static_cast<size_type>((slash + 1) - m_buffer.c_str());
  933. }
  934. else
  935. {
  936. clear();
  937. }
  938. if(bRemoveTrailingPathNameSeparator)
  939. {
  940. this->pop_sep();
  941. }
  942. return *this;
  943. }
  944. template< ss_typename_param_k C
  945. , ss_typename_param_k T
  946. , ss_typename_param_k A
  947. >
  948. inline basic_path<C, T, A>& basic_path<C, T, A>::pop_sep()
  949. {
  950. if(0 != m_len)
  951. {
  952. if( 1 == m_len &&
  953. traits_type::is_path_name_separator(m_buffer[0]))
  954. {
  955. // It's / or \ - ignore
  956. }
  957. #ifdef _WIN32
  958. else if(3 == m_len &&
  959. ':' == m_buffer[1] &&
  960. traits_type::is_path_name_separator(m_buffer[2]))
  961. {
  962. // It's drive rooted - ignore
  963. }
  964. #endif /* _WIN32 */
  965. else
  966. {
  967. char_type* last = &m_buffer[m_len - 1];
  968. if(*last == traits_type::path_name_separator())
  969. {
  970. m_buffer[m_len-- - 1] = '\0';
  971. }
  972. #ifdef _WIN32
  973. else if(*last == path_name_separator_alt())
  974. {
  975. m_buffer[m_len-- - 1] = '\0';
  976. }
  977. #endif /* _WIN32 */
  978. }
  979. }
  980. return *this;
  981. }
  982. template< ss_typename_param_k C
  983. , ss_typename_param_k T
  984. , ss_typename_param_k A
  985. >
  986. inline basic_path<C, T, A>& basic_path<C, T, A>::pop_ext()
  987. {
  988. { for(us_size_t len = m_len; 0 != len; --len)
  989. {
  990. char_type* last = &m_buffer[len - 1];
  991. if(traits_type::is_path_name_separator(*last))
  992. {
  993. break;
  994. }
  995. else if('.' == *last)
  996. {
  997. m_len = len - 1;
  998. m_buffer[m_len] = '\0';
  999. break;
  1000. }
  1001. }}
  1002. return *this;
  1003. }
  1004. #if !defined(STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT) || \
  1005. defined(STLSOFT_CF_MEMBER_TEMPLATE_OVERLOAD_DISCRIMINATED)
  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>::operator /=(basic_path<C, T, A> const& path)
  1011. {
  1012. return push(path);
  1013. }
  1014. #endif /* !STLSOFT_CF_MEMBER_TEMPLATE_FUNCTION_SUPPORT || STLSOFT_CF_MEMBER_TEMPLATE_OVERLOAD_DISCRIMINATED */
  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>& basic_path<C, T, A>::operator /=(ss_typename_type_k basic_path<C, T, A>::char_type const* path)
  1020. {
  1021. return push(path);
  1022. }
  1023. template< ss_typename_param_k C
  1024. , ss_typename_param_k T
  1025. , ss_typename_param_k A
  1026. >
  1027. inline void basic_path<C, T, A>::clear()
  1028. {
  1029. m_buffer[0] = '\0';
  1030. m_len = 0;
  1031. }
  1032. template< ss_typename_param_k C
  1033. , ss_typename_param_k T
  1034. , ss_typename_param_k A
  1035. >
  1036. inline basic_path<C, T, A>& basic_path<C, T, A>::make_absolute(us_bool_t bRemoveTrailingPathNameSeparator /* = true */)
  1037. {
  1038. if(0 != size())
  1039. {
  1040. buffer_type_ buffer;
  1041. size_type cch = traits_type::get_full_path_name(c_str(), buffer.size(), &buffer[0]);
  1042. if(0 == cch)
  1043. {
  1044. #ifdef STLSOFT_CF_EXCEPTION_SUPPORT
  1045. STLSOFT_THROW_X(unix_exception("could not determine the absolute path", errno));
  1046. #else /* ?STLSOFT_CF_EXCEPTION_SUPPORT */
  1047. return *this;
  1048. #endif /* STLSOFT_CF_EXCEPTION_SUPPORT */
  1049. }
  1050. class_type newPath(buffer.c_str(), cch);
  1051. if(bRemoveTrailingPathNameSeparator)
  1052. {
  1053. newPath.pop_sep();
  1054. }
  1055. swap(newPath);
  1056. }
  1057. return *this;
  1058. }
  1059. template< ss_typename_param_k C
  1060. , ss_typename_param_k T
  1061. , ss_typename_param_k A
  1062. >
  1063. inline basic_path<C, T, A>& basic_path<C, T, A>::canonicalise(us_bool_t bRemoveTrailingPathNameSeparator /* = true */)
  1064. {
  1065. class_type newPath(*this);
  1066. #ifdef _DEBUG
  1067. memset(&newPath.m_buffer[0], '~', newPath.m_buffer.size());
  1068. #endif /* _DEBUG */
  1069. // Basically we scan through the path looking for ./ .\ ..\ and ../
  1070. #ifdef STLSOFT_LF_ALLOCATOR_REBIND_SUPPORT
  1071. typedef ss_typename_type_k A::ss_template_qual_k rebind<part>::other part_ator_type;
  1072. #else /* ? STLSOFT_LF_ALLOCATOR_REBIND_SUPPORT */
  1073. typedef ss_typename_type_k allocator_selector<part>::allocator_type part_ator_type;
  1074. #endif /* STLSOFT_LF_ALLOCATOR_REBIND_SUPPORT */
  1075. typedef stlsoft_ns_qual(auto_buffer_old)< part
  1076. , part_ator_type
  1077. > part_buffer_t;
  1078. part_buffer_t parts(this->length() / 2); // Uncanonicalised directory parts
  1079. char_type* dest = &newPath.m_buffer[0];
  1080. char_type const* p1 = this->c_str();
  1081. char_type const* p2;
  1082. if(this->is_absolute())
  1083. {
  1084. #ifdef _WIN32
  1085. if(traits_type::is_path_UNC(this->c_str()))
  1086. {
  1087. UNIXSTL_ASSERT('\\' == m_buffer[0]);
  1088. UNIXSTL_ASSERT('\\' == m_buffer[1]);
  1089. UNIXSTL_ASSERT('\\' != m_buffer[2]);
  1090. char_type const* slash0 = next_slash_or_end(&m_buffer[3]);
  1091. char_type const* slash1 = next_slash_or_end(slash0);
  1092. for(us_size_t i = 0, n = slash1 - &m_buffer[0]; i < n; ++i)
  1093. {
  1094. *dest++ = *p1++;
  1095. }
  1096. }
  1097. else if( isalpha(m_buffer[0]) &&
  1098. ':' == m_buffer[1])
  1099. {
  1100. // Copy over the drive letter, colon and slash
  1101. *dest++ = *p1++;
  1102. *dest++ = *p1++;
  1103. *dest++ = *p1++;
  1104. }
  1105. else
  1106. #endif /* _WIN32 */
  1107. {
  1108. *dest++ = traits_type::path_name_separator();
  1109. ++p1;
  1110. }
  1111. }
  1112. // 1. Parse the path into an uncanonicalised sequence of directory parts
  1113. {
  1114. size_type i = 0;
  1115. for(; '\0' != *p1; ++i)
  1116. {
  1117. p2 = next_slash_or_end(p1);
  1118. parts[i].len = static_cast<size_type>(p2 - p1);
  1119. parts[i].p = p1;
  1120. parts[i].type = part::normal;
  1121. switch(parts[i].len)
  1122. {
  1123. case 1:
  1124. if('.' == p1[0])
  1125. {
  1126. parts[i].type = part::dot;
  1127. }
  1128. break;
  1129. case 2:
  1130. if('.' == p1[0])
  1131. {
  1132. if('.' == p1[1])
  1133. {
  1134. parts[i].type = part::dotdot;
  1135. }
  1136. else if(traits_type::path_name_separator() == p1[1])
  1137. {
  1138. parts[i].type = part::dot;
  1139. }
  1140. #ifdef _WIN32
  1141. else if(path_name_separator_alt() == p1[1])
  1142. {
  1143. parts[i].type = part::dot;
  1144. }
  1145. #endif /* _WIN32 */
  1146. }
  1147. break;
  1148. case 3:
  1149. if( '.' == p1[0] &&
  1150. '.' == p1[1])
  1151. {
  1152. if(traits_type::path_name_separator() == p1[2])
  1153. {
  1154. parts[i].type = part::dotdot;
  1155. }
  1156. #ifdef _WIN32
  1157. else if(path_name_separator_alt() == p1[2])
  1158. {
  1159. parts[i].type = part::dotdot;
  1160. }
  1161. #endif /* _WIN32 */
  1162. }
  1163. break;
  1164. default:
  1165. break;
  1166. }
  1167. p1 = p2;
  1168. }
  1169. parts.resize(i);
  1170. }
  1171. // 2. Process the parts into a canonicalised sequence
  1172. {
  1173. size_type i = 0;
  1174. for(i = 0; i < parts.size(); ++i)
  1175. {
  1176. switch(parts[i].type)
  1177. {
  1178. case part::dot:
  1179. parts[i].len = 0;
  1180. break;
  1181. case part::dotdot:
  1182. // Now need to track back and find a prior normal element
  1183. {
  1184. size_type prior;
  1185. for(prior = i; ; )
  1186. {
  1187. if(0 == prior)
  1188. {
  1189. STLSOFT_THROW_X(unixstl_ns_qual_std(invalid_argument)("No prior part to \"..\" for path canonicalisation"));
  1190. }
  1191. else
  1192. {
  1193. --prior;
  1194. if( part::normal == parts[prior].type &&
  1195. 0 != parts[prior].len)
  1196. {
  1197. parts[i].len = 0;
  1198. parts[prior].len = 0;
  1199. break;
  1200. }
  1201. }
  1202. }
  1203. }
  1204. break;
  1205. case part::normal:
  1206. default:
  1207. break;
  1208. }
  1209. }
  1210. }
  1211. // 3. Write out all the parts back into the new path instance
  1212. {
  1213. size_type i = 0;
  1214. #ifdef _DEBUG
  1215. memset(dest, '~', newPath.m_buffer.size() - (dest - &newPath.m_buffer[0]));
  1216. #endif /* _DEBUG */
  1217. for(i = 0; i < parts.size(); ++i)
  1218. {
  1219. traits_type::char_copy(dest, parts[i].p, parts[i].len);
  1220. dest += parts[i].len;
  1221. }
  1222. *dest = '\0';
  1223. newPath.m_len = dest - newPath.c_str();
  1224. }
  1225. if(bRemoveTrailingPathNameSeparator)
  1226. {
  1227. newPath.pop_sep();
  1228. }
  1229. swap(newPath);
  1230. return *this;
  1231. }
  1232. template< ss_typename_param_k C
  1233. , ss_typename_param_k T
  1234. , ss_typename_param_k A
  1235. >
  1236. inline ss_typename_type_ret_k basic_path<C, T, A>::char_type const* basic_path<C, T, A>::get_file() const
  1237. {
  1238. char_type const* slash = traits_type::str_rchr(m_buffer.c_str(), traits_type::path_name_separator());
  1239. char_type const* slash_a = traits_type::str_rchr(m_buffer.c_str(), path_name_separator_alt());
  1240. if(slash_a > slash)
  1241. {
  1242. slash = slash_a;
  1243. }
  1244. if(NULL == slash)
  1245. {
  1246. slash = m_buffer.c_str();
  1247. }
  1248. else
  1249. {
  1250. ++slash;
  1251. }
  1252. return slash;
  1253. }
  1254. template< ss_typename_param_k C
  1255. , ss_typename_param_k T
  1256. , ss_typename_param_k A
  1257. >
  1258. inline ss_typename_type_ret_k basic_path<C, T, A>::char_type const* basic_path<C, T, A>::get_ext() const
  1259. {
  1260. char_type const *dot = traits_type::str_rchr(this->c_str(), '.');
  1261. char_type const *file = get_file();
  1262. static const char_type s_empty[1] = { '\0' };
  1263. if(NULL == dot)
  1264. {
  1265. return s_empty;
  1266. }
  1267. else if(dot < file)
  1268. {
  1269. return s_empty;
  1270. }
  1271. else
  1272. {
  1273. return dot + 1;
  1274. }
  1275. }
  1276. template< ss_typename_param_k C
  1277. , ss_typename_param_k T
  1278. , ss_typename_param_k A
  1279. >
  1280. inline ss_typename_type_ret_k basic_path<C, T, A>::size_type basic_path<C, T, A>::length() const
  1281. {
  1282. return m_len;
  1283. }
  1284. template< ss_typename_param_k C
  1285. , ss_typename_param_k T
  1286. , ss_typename_param_k A
  1287. >
  1288. inline ss_typename_type_ret_k basic_path<C, T, A>::size_type basic_path<C, T, A>::size() const
  1289. {
  1290. return length();
  1291. }
  1292. template< ss_typename_param_k C
  1293. , ss_typename_param_k T
  1294. , ss_typename_param_k A
  1295. >
  1296. inline ss_typename_type_ret_k basic_path<C, T, A>::size_type
  1297. /* static */ basic_path<C, T, A>::max_size()
  1298. {
  1299. return buffer_type_::max_size() - 1u;
  1300. }
  1301. template< ss_typename_param_k C
  1302. , ss_typename_param_k T
  1303. , ss_typename_param_k A
  1304. >
  1305. inline ss_typename_type_ret_k basic_path<C, T, A>::bool_type basic_path<C, T, A>::empty() const
  1306. {
  1307. return 0 == size();
  1308. }
  1309. template< ss_typename_param_k C
  1310. , ss_typename_param_k T
  1311. , ss_typename_param_k A
  1312. >
  1313. inline ss_typename_type_ret_k basic_path<C, T, A>::char_type const* basic_path<C, T, A>::c_str() const
  1314. {
  1315. return m_buffer.c_str();
  1316. }
  1317. template< ss_typename_param_k C
  1318. , ss_typename_param_k T
  1319. , ss_typename_param_k A
  1320. >
  1321. 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
  1322. {
  1323. UNIXSTL_MESSAGE_ASSERT("Index out of range", !(size() < index));
  1324. return c_str()[index];
  1325. }
  1326. template< ss_typename_param_k C
  1327. , ss_typename_param_k T
  1328. , ss_typename_param_k A
  1329. >
  1330. inline us_bool_t basic_path<C, T, A>::exists() const
  1331. {
  1332. return traits_type::file_exists(this->c_str());
  1333. }
  1334. template< ss_typename_param_k C
  1335. , ss_typename_param_k T
  1336. , ss_typename_param_k A
  1337. >
  1338. inline us_bool_t basic_path<C, T, A>::is_rooted() const
  1339. {
  1340. return traits_type::is_path_rooted(this->c_str());
  1341. }
  1342. template< ss_typename_param_k C
  1343. , ss_typename_param_k T
  1344. , ss_typename_param_k A
  1345. >
  1346. inline us_bool_t basic_path<C, T, A>::is_absolute() const
  1347. {
  1348. return traits_type::is_path_absolute(this->c_str());
  1349. }
  1350. template< ss_typename_param_k C
  1351. , ss_typename_param_k T
  1352. , ss_typename_param_k A
  1353. >
  1354. inline us_bool_t basic_path<C, T, A>::has_sep() const
  1355. {
  1356. return this->empty() ? false : traits_type::has_dir_end(this->c_str() + (this->size() - 1));
  1357. }
  1358. template< ss_typename_param_k C
  1359. , ss_typename_param_k T
  1360. , ss_typename_param_k A
  1361. >
  1362. 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
  1363. {
  1364. return stlsoft_ns_qual(copy_contents)(buffer, cchBuffer, m_buffer.data(), m_len);
  1365. }
  1366. template< ss_typename_param_k C
  1367. , ss_typename_param_k T
  1368. , ss_typename_param_k A
  1369. >
  1370. inline us_bool_t basic_path<C, T, A>::equivalent(basic_path<C, T, A> const& rhs) const
  1371. {
  1372. return equivalent(rhs.c_str());
  1373. }
  1374. template< ss_typename_param_k C
  1375. , ss_typename_param_k T
  1376. , ss_typename_param_k A
  1377. >
  1378. inline us_bool_t basic_path<C, T, A>::equivalent(ss_typename_type_k basic_path<C, T, A>::char_type const* rhs) const
  1379. {
  1380. class_type lhs_(*this);
  1381. class_type rhs_(rhs);
  1382. return lhs_.make_absolute(false).canonicalise(true) == rhs_.make_absolute(false).canonicalise(true);
  1383. }
  1384. template< ss_typename_param_k C
  1385. , ss_typename_param_k T
  1386. , ss_typename_param_k A
  1387. >
  1388. inline us_bool_t basic_path<C, T, A>::equal(basic_path<C, T, A> const& rhs) const
  1389. {
  1390. return equal(rhs.c_str());
  1391. }
  1392. template< ss_typename_param_k C
  1393. , ss_typename_param_k T
  1394. , ss_typename_param_k A
  1395. >
  1396. inline us_bool_t basic_path<C, T, A>::equal(ss_typename_type_k basic_path<C, T, A>::char_type const* rhs) const
  1397. {
  1398. return 0 == traits_type::str_compare(m_buffer.c_str(), stlsoft_ns_qual(c_str_ptr)(rhs));
  1399. }
  1400. #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */
  1401. /* ////////////////////////////////////////////////////////////////////// */
  1402. #ifndef _UNIXSTL_NO_NAMESPACE
  1403. # if defined(_STLSOFT_NO_NAMESPACE) || \
  1404. defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  1405. } // namespace unixstl
  1406. # else
  1407. } // namespace unixstl_project
  1408. } // namespace stlsoft
  1409. # endif /* _STLSOFT_NO_NAMESPACE */
  1410. #endif /* !_UNIXSTL_NO_NAMESPACE */
  1411. /* In the special case of Intel behaving as VC++ 7.0 or earlier on Win32, we
  1412. * illegally insert into the std namespace.
  1413. */
  1414. #if defined(STLSOFT_CF_std_NAMESPACE)
  1415. # if ( ( defined(STLSOFT_COMPILER_IS_INTEL) && \
  1416. defined(_MSC_VER))) && \
  1417. _MSC_VER < 1310
  1418. namespace std
  1419. {
  1420. template< ss_typename_param_k C
  1421. , ss_typename_param_k T
  1422. , ss_typename_param_k A
  1423. >
  1424. inline void swap(unixstl_ns_qual(basic_path)<C, T, A>& lhs, unixstl_ns_qual(basic_path)<C, T, A>& rhs)
  1425. {
  1426. lhs.swap(rhs);
  1427. }
  1428. } // namespace std
  1429. # endif /* INTEL && _MSC_VER < 1310 */
  1430. #endif /* STLSOFT_CF_std_NAMESPACE */
  1431. /* /////////////////////////////////////////////////////////////////////////
  1432. * Namespace
  1433. *
  1434. * The string access shims exist either in the stlsoft namespace, or in the
  1435. * global namespace. This is required by the lookup rules.
  1436. *
  1437. */
  1438. #ifndef _UNIXSTL_NO_NAMESPACE
  1439. # if !defined(_STLSOFT_NO_NAMESPACE) && \
  1440. !defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  1441. namespace stlsoft
  1442. {
  1443. # else /* ? _STLSOFT_NO_NAMESPACE */
  1444. /* There is no stlsoft namespace, so must define in the global namespace */
  1445. # endif /* !_STLSOFT_NO_NAMESPACE */
  1446. using ::unixstl::c_str_data;
  1447. using ::unixstl::c_str_data_a;
  1448. using ::unixstl::c_str_data_w;
  1449. using ::unixstl::c_str_len;
  1450. using ::unixstl::c_str_len_a;
  1451. using ::unixstl::c_str_len_w;
  1452. using ::unixstl::c_str_ptr;
  1453. using ::unixstl::c_str_ptr_a;
  1454. using ::unixstl::c_str_ptr_w;
  1455. using ::unixstl::c_str_ptr_null;
  1456. using ::unixstl::c_str_ptr_null_a;
  1457. using ::unixstl::c_str_ptr_null_w;
  1458. # if !defined(_STLSOFT_NO_NAMESPACE) && \
  1459. !defined(STLSOFT_DOCUMENTATION_SKIP_SECTION)
  1460. } // namespace stlsoft
  1461. # else /* ? _STLSOFT_NO_NAMESPACE */
  1462. /* There is no stlsoft namespace, so must define in the global namespace */
  1463. # endif /* !_STLSOFT_NO_NAMESPACE */
  1464. #endif /* !_UNIXSTL_NO_NAMESPACE */
  1465. /* ////////////////////////////////////////////////////////////////////// */
  1466. #endif /* UNIXSTL_INCL_UNIXSTL_FILESYSTEM_HPP_PATH */
  1467. /* ///////////////////////////// end of file //////////////////////////// */