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.

1364 lines
38KB

  1. // Class filesystem::path -*- C++ -*-
  2. // Copyright (C) 2014-2020 Free Software Foundation, Inc.
  3. //
  4. // This file is part of the GNU ISO C++ Library. This library is free
  5. // software; you can redistribute it and/or modify it under the
  6. // terms of the GNU General Public License as published by the
  7. // Free Software Foundation; either version 3, or (at your option)
  8. // any later version.
  9. // This library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // Under Section 7 of GPL version 3, you are granted additional
  14. // permissions described in the GCC Runtime Library Exception, version
  15. // 3.1, as published by the Free Software Foundation.
  16. // You should have received a copy of the GNU General Public License and
  17. // a copy of the GCC Runtime Library Exception along with this program;
  18. // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  19. // <http://www.gnu.org/licenses/>.
  20. /** @file include/bits/fs_path.h
  21. * This is an internal header file, included by other library headers.
  22. * Do not attempt to use it directly. @headername{filesystem}
  23. */
  24. #ifndef _GLIBCXX_FS_PATH_H
  25. #define _GLIBCXX_FS_PATH_H 1
  26. #if __cplusplus >= 201703L
  27. #include <utility>
  28. #include <type_traits>
  29. #include <locale>
  30. #include <iosfwd>
  31. #include <iomanip>
  32. #include <codecvt>
  33. #include <string_view>
  34. #include <system_error>
  35. #include <bits/stl_algobase.h>
  36. #include <bits/locale_conv.h>
  37. #include <ext/concurrence.h>
  38. #include <bits/shared_ptr.h>
  39. #include <bits/unique_ptr.h>
  40. #if __cplusplus > 201703L
  41. # include <compare>
  42. #endif
  43. #if defined(_WIN32) && !defined(__CYGWIN__)
  44. # define _GLIBCXX_FILESYSTEM_IS_WINDOWS 1
  45. # include <algorithm>
  46. #endif
  47. namespace std _GLIBCXX_VISIBILITY(default)
  48. {
  49. _GLIBCXX_BEGIN_NAMESPACE_VERSION
  50. namespace filesystem
  51. {
  52. _GLIBCXX_BEGIN_NAMESPACE_CXX11
  53. /** @addtogroup filesystem
  54. * @{
  55. */
  56. class path;
  57. /// @cond undocumented
  58. namespace __detail
  59. {
  60. template<typename _CharT>
  61. using __is_encoded_char = __is_one_of<remove_const_t<_CharT>,
  62. char,
  63. #ifdef _GLIBCXX_USE_CHAR8_T
  64. char8_t,
  65. #endif
  66. #if _GLIBCXX_USE_WCHAR_T
  67. wchar_t,
  68. #endif
  69. char16_t, char32_t>;
  70. template<typename _Iter,
  71. typename _Iter_traits = std::iterator_traits<_Iter>>
  72. using __is_path_iter_src
  73. = __and_<__is_encoded_char<typename _Iter_traits::value_type>,
  74. std::is_base_of<std::input_iterator_tag,
  75. typename _Iter_traits::iterator_category>>;
  76. template<typename _Iter>
  77. static __is_path_iter_src<_Iter>
  78. __is_path_src(_Iter, int);
  79. template<typename _CharT, typename _Traits, typename _Alloc>
  80. static __is_encoded_char<_CharT>
  81. __is_path_src(const basic_string<_CharT, _Traits, _Alloc>&, int);
  82. template<typename _CharT, typename _Traits>
  83. static __is_encoded_char<_CharT>
  84. __is_path_src(const basic_string_view<_CharT, _Traits>&, int);
  85. template<typename _Unknown>
  86. static std::false_type
  87. __is_path_src(const _Unknown&, ...);
  88. template<typename _Tp1, typename _Tp2>
  89. struct __constructible_from;
  90. template<typename _Iter>
  91. struct __constructible_from<_Iter, _Iter>
  92. : __is_path_iter_src<_Iter>
  93. { };
  94. template<typename _Source>
  95. struct __constructible_from<_Source, void>
  96. : decltype(__is_path_src(std::declval<_Source>(), 0))
  97. { };
  98. template<typename _Tp1, typename _Tp2 = void>
  99. using _Path = typename
  100. std::enable_if<__and_<__not_<is_same<remove_cv_t<_Tp1>, path>>,
  101. __not_<is_void<remove_pointer_t<_Tp1>>>,
  102. __constructible_from<_Tp1, _Tp2>>::value,
  103. path>::type;
  104. template<typename _Source>
  105. _Source
  106. _S_range_begin(_Source __begin) { return __begin; }
  107. struct __null_terminated { };
  108. template<typename _Source>
  109. __null_terminated
  110. _S_range_end(_Source) { return {}; }
  111. template<typename _CharT, typename _Traits, typename _Alloc>
  112. inline const _CharT*
  113. _S_range_begin(const basic_string<_CharT, _Traits, _Alloc>& __str)
  114. { return __str.data(); }
  115. template<typename _CharT, typename _Traits, typename _Alloc>
  116. inline const _CharT*
  117. _S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str)
  118. { return __str.data() + __str.size(); }
  119. template<typename _CharT, typename _Traits>
  120. inline const _CharT*
  121. _S_range_begin(const basic_string_view<_CharT, _Traits>& __str)
  122. { return __str.data(); }
  123. template<typename _CharT, typename _Traits>
  124. inline const _CharT*
  125. _S_range_end(const basic_string_view<_CharT, _Traits>& __str)
  126. { return __str.data() + __str.size(); }
  127. template<typename _Tp,
  128. typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())),
  129. typename _Val = typename std::iterator_traits<_Iter>::value_type,
  130. typename _UnqualVal = std::remove_const_t<_Val>>
  131. using __value_type_is_char
  132. = std::enable_if_t<std::is_same_v<_UnqualVal, char>,
  133. _UnqualVal>;
  134. template<typename _Tp,
  135. typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())),
  136. typename _Val = typename std::iterator_traits<_Iter>::value_type,
  137. typename _UnqualVal = std::remove_const_t<_Val>>
  138. using __value_type_is_char_or_char8_t
  139. = std::enable_if_t<__or_v<
  140. std::is_same<_UnqualVal, char>
  141. #ifdef _GLIBCXX_USE_CHAR8_T
  142. , std::is_same<_UnqualVal, char8_t>
  143. #endif
  144. >,
  145. _UnqualVal>;
  146. } // namespace __detail
  147. /// @endcond
  148. /// A filesystem path.
  149. class path
  150. {
  151. public:
  152. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  153. using value_type = wchar_t;
  154. static constexpr value_type preferred_separator = L'\\';
  155. #else
  156. # ifdef _GLIBCXX_DOXYGEN
  157. /// Windows uses wchar_t for path::value_type, POSIX uses char.
  158. using value_type = __os_dependent__;
  159. # else
  160. using value_type = char;
  161. # endif
  162. static constexpr value_type preferred_separator = '/';
  163. #endif
  164. using string_type = std::basic_string<value_type>;
  165. /// path::format is ignored in this implementation
  166. enum format : unsigned char { native_format, generic_format, auto_format };
  167. // constructors and destructor
  168. path() noexcept { }
  169. path(const path& __p) = default;
  170. path(path&& __p)
  171. #if _GLIBCXX_USE_CXX11_ABI || _GLIBCXX_FULLY_DYNAMIC_STRING == 0
  172. noexcept
  173. #endif
  174. : _M_pathname(std::move(__p._M_pathname)),
  175. _M_cmpts(std::move(__p._M_cmpts))
  176. { __p.clear(); }
  177. path(string_type&& __source, format = auto_format)
  178. : _M_pathname(std::move(__source))
  179. { _M_split_cmpts(); }
  180. template<typename _Source,
  181. typename _Require = __detail::_Path<_Source>>
  182. path(_Source const& __source, format = auto_format)
  183. : _M_pathname(_S_convert(__detail::_S_range_begin(__source),
  184. __detail::_S_range_end(__source)))
  185. { _M_split_cmpts(); }
  186. template<typename _InputIterator,
  187. typename _Require = __detail::_Path<_InputIterator, _InputIterator>>
  188. path(_InputIterator __first, _InputIterator __last, format = auto_format)
  189. : _M_pathname(_S_convert(__first, __last))
  190. { _M_split_cmpts(); }
  191. template<typename _Source,
  192. typename _Require = __detail::_Path<_Source>,
  193. typename _Require2 = __detail::__value_type_is_char<_Source>>
  194. path(_Source const& __source, const locale& __loc, format = auto_format)
  195. : _M_pathname(_S_convert_loc(__detail::_S_range_begin(__source),
  196. __detail::_S_range_end(__source), __loc))
  197. { _M_split_cmpts(); }
  198. template<typename _InputIterator,
  199. typename _Require = __detail::_Path<_InputIterator, _InputIterator>,
  200. typename _Require2 = __detail::__value_type_is_char<_InputIterator>>
  201. path(_InputIterator __first, _InputIterator __last, const locale& __loc,
  202. format = auto_format)
  203. : _M_pathname(_S_convert_loc(__first, __last, __loc))
  204. { _M_split_cmpts(); }
  205. ~path() = default;
  206. // assignments
  207. path& operator=(const path&);
  208. path& operator=(path&&) noexcept;
  209. path& operator=(string_type&& __source);
  210. path& assign(string_type&& __source);
  211. template<typename _Source>
  212. __detail::_Path<_Source>&
  213. operator=(_Source const& __source)
  214. { return *this = path(__source); }
  215. template<typename _Source>
  216. __detail::_Path<_Source>&
  217. assign(_Source const& __source)
  218. { return *this = path(__source); }
  219. template<typename _InputIterator>
  220. __detail::_Path<_InputIterator, _InputIterator>&
  221. assign(_InputIterator __first, _InputIterator __last)
  222. { return *this = path(__first, __last); }
  223. // appends
  224. path& operator/=(const path& __p);
  225. template<typename _Source>
  226. __detail::_Path<_Source>&
  227. operator/=(_Source const& __source)
  228. {
  229. _M_append(_S_convert(__detail::_S_range_begin(__source),
  230. __detail::_S_range_end(__source)));
  231. return *this;
  232. }
  233. template<typename _Source>
  234. __detail::_Path<_Source>&
  235. append(_Source const& __source)
  236. {
  237. _M_append(_S_convert(__detail::_S_range_begin(__source),
  238. __detail::_S_range_end(__source)));
  239. return *this;
  240. }
  241. template<typename _InputIterator>
  242. __detail::_Path<_InputIterator, _InputIterator>&
  243. append(_InputIterator __first, _InputIterator __last)
  244. {
  245. _M_append(_S_convert(__first, __last));
  246. return *this;
  247. }
  248. // concatenation
  249. path& operator+=(const path& __x);
  250. path& operator+=(const string_type& __x);
  251. path& operator+=(const value_type* __x);
  252. path& operator+=(value_type __x);
  253. path& operator+=(basic_string_view<value_type> __x);
  254. template<typename _Source>
  255. __detail::_Path<_Source>&
  256. operator+=(_Source const& __x) { return concat(__x); }
  257. template<typename _CharT>
  258. __detail::_Path<_CharT*, _CharT*>&
  259. operator+=(_CharT __x);
  260. template<typename _Source>
  261. __detail::_Path<_Source>&
  262. concat(_Source const& __x)
  263. {
  264. _M_concat(_S_convert(__detail::_S_range_begin(__x),
  265. __detail::_S_range_end(__x)));
  266. return *this;
  267. }
  268. template<typename _InputIterator>
  269. __detail::_Path<_InputIterator, _InputIterator>&
  270. concat(_InputIterator __first, _InputIterator __last)
  271. {
  272. _M_concat(_S_convert(__first, __last));
  273. return *this;
  274. }
  275. // modifiers
  276. void clear() noexcept { _M_pathname.clear(); _M_split_cmpts(); }
  277. path& make_preferred();
  278. path& remove_filename();
  279. path& replace_filename(const path& __replacement);
  280. path& replace_extension(const path& __replacement = path());
  281. void swap(path& __rhs) noexcept;
  282. // native format observers
  283. const string_type& native() const noexcept { return _M_pathname; }
  284. const value_type* c_str() const noexcept { return _M_pathname.c_str(); }
  285. operator string_type() const { return _M_pathname; }
  286. template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
  287. typename _Allocator = std::allocator<_CharT>>
  288. std::basic_string<_CharT, _Traits, _Allocator>
  289. string(const _Allocator& __a = _Allocator()) const;
  290. std::string string() const;
  291. #if _GLIBCXX_USE_WCHAR_T
  292. std::wstring wstring() const;
  293. #endif
  294. #ifdef _GLIBCXX_USE_CHAR8_T
  295. __attribute__((__abi_tag__("__u8")))
  296. std::u8string u8string() const;
  297. #else
  298. std::string u8string() const;
  299. #endif // _GLIBCXX_USE_CHAR8_T
  300. std::u16string u16string() const;
  301. std::u32string u32string() const;
  302. // generic format observers
  303. template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
  304. typename _Allocator = std::allocator<_CharT>>
  305. std::basic_string<_CharT, _Traits, _Allocator>
  306. generic_string(const _Allocator& __a = _Allocator()) const;
  307. std::string generic_string() const;
  308. #if _GLIBCXX_USE_WCHAR_T
  309. std::wstring generic_wstring() const;
  310. #endif
  311. #ifdef _GLIBCXX_USE_CHAR8_T
  312. __attribute__((__abi_tag__("__u8")))
  313. std::u8string generic_u8string() const;
  314. #else
  315. std::string generic_u8string() const;
  316. #endif // _GLIBCXX_USE_CHAR8_T
  317. std::u16string generic_u16string() const;
  318. std::u32string generic_u32string() const;
  319. // compare
  320. int compare(const path& __p) const noexcept;
  321. int compare(const string_type& __s) const noexcept;
  322. int compare(const value_type* __s) const noexcept;
  323. int compare(basic_string_view<value_type> __s) const noexcept;
  324. // decomposition
  325. path root_name() const;
  326. path root_directory() const;
  327. path root_path() const;
  328. path relative_path() const;
  329. path parent_path() const;
  330. path filename() const;
  331. path stem() const;
  332. path extension() const;
  333. // query
  334. [[nodiscard]] bool empty() const noexcept { return _M_pathname.empty(); }
  335. bool has_root_name() const noexcept;
  336. bool has_root_directory() const noexcept;
  337. bool has_root_path() const noexcept;
  338. bool has_relative_path() const noexcept;
  339. bool has_parent_path() const noexcept;
  340. bool has_filename() const noexcept;
  341. bool has_stem() const noexcept;
  342. bool has_extension() const noexcept;
  343. bool is_absolute() const noexcept;
  344. bool is_relative() const noexcept { return !is_absolute(); }
  345. // generation
  346. path lexically_normal() const;
  347. path lexically_relative(const path& base) const;
  348. path lexically_proximate(const path& base) const;
  349. // iterators
  350. class iterator;
  351. using const_iterator = iterator;
  352. iterator begin() const;
  353. iterator end() const;
  354. /// Write a path to a stream
  355. template<typename _CharT, typename _Traits>
  356. friend std::basic_ostream<_CharT, _Traits>&
  357. operator<<(std::basic_ostream<_CharT, _Traits>& __os, const path& __p)
  358. {
  359. __os << std::quoted(__p.string<_CharT, _Traits>());
  360. return __os;
  361. }
  362. /// Read a path from a stream
  363. template<typename _CharT, typename _Traits>
  364. friend std::basic_istream<_CharT, _Traits>&
  365. operator>>(std::basic_istream<_CharT, _Traits>& __is, path& __p)
  366. {
  367. std::basic_string<_CharT, _Traits> __tmp;
  368. if (__is >> std::quoted(__tmp))
  369. __p = std::move(__tmp);
  370. return __is;
  371. }
  372. // non-member operators
  373. /// Compare paths
  374. friend bool operator==(const path& __lhs, const path& __rhs) noexcept
  375. { return __lhs.compare(__rhs) == 0; }
  376. #if __cpp_lib_three_way_comparison
  377. /// Compare paths
  378. friend strong_ordering
  379. operator<=>(const path& __lhs, const path& __rhs) noexcept
  380. { return __lhs.compare(__rhs) <=> 0; }
  381. #else
  382. /// Compare paths
  383. friend bool operator!=(const path& __lhs, const path& __rhs) noexcept
  384. { return !(__lhs == __rhs); }
  385. /// Compare paths
  386. friend bool operator<(const path& __lhs, const path& __rhs) noexcept
  387. { return __lhs.compare(__rhs) < 0; }
  388. /// Compare paths
  389. friend bool operator<=(const path& __lhs, const path& __rhs) noexcept
  390. { return !(__rhs < __lhs); }
  391. /// Compare paths
  392. friend bool operator>(const path& __lhs, const path& __rhs) noexcept
  393. { return __rhs < __lhs; }
  394. /// Compare paths
  395. friend bool operator>=(const path& __lhs, const path& __rhs) noexcept
  396. { return !(__lhs < __rhs); }
  397. #endif
  398. /// Append one path to another
  399. friend path operator/(const path& __lhs, const path& __rhs)
  400. {
  401. path __result(__lhs);
  402. __result /= __rhs;
  403. return __result;
  404. }
  405. /// @cond undocumented
  406. // Create a basic_string by reading until a null character.
  407. template<typename _InputIterator,
  408. typename _Traits = std::iterator_traits<_InputIterator>,
  409. typename _CharT
  410. = typename std::remove_cv_t<typename _Traits::value_type>>
  411. static std::basic_string<_CharT>
  412. _S_string_from_iter(_InputIterator __source)
  413. {
  414. std::basic_string<_CharT> __str;
  415. for (_CharT __ch = *__source; __ch != _CharT(); __ch = *++__source)
  416. __str.push_back(__ch);
  417. return __str;
  418. }
  419. /// @endcond
  420. private:
  421. enum class _Type : unsigned char {
  422. _Multi = 0, _Root_name, _Root_dir, _Filename
  423. };
  424. path(basic_string_view<value_type> __str, _Type __type)
  425. : _M_pathname(__str)
  426. {
  427. __glibcxx_assert(__type != _Type::_Multi);
  428. _M_cmpts.type(__type);
  429. }
  430. enum class _Split { _Stem, _Extension };
  431. void _M_append(basic_string_view<value_type>);
  432. void _M_concat(basic_string_view<value_type>);
  433. pair<const string_type*, size_t> _M_find_extension() const noexcept;
  434. template<typename _CharT>
  435. struct _Cvt;
  436. static basic_string_view<value_type>
  437. _S_convert(value_type* __src, __detail::__null_terminated)
  438. { return __src; }
  439. static basic_string_view<value_type>
  440. _S_convert(const value_type* __src, __detail::__null_terminated)
  441. { return __src; }
  442. static basic_string_view<value_type>
  443. _S_convert(value_type* __first, value_type* __last)
  444. { return {__first, __last - __first}; }
  445. static basic_string_view<value_type>
  446. _S_convert(const value_type* __first, const value_type* __last)
  447. { return {__first, __last - __first}; }
  448. template<typename _Iter>
  449. static string_type
  450. _S_convert(_Iter __first, _Iter __last)
  451. {
  452. using __value_type = typename std::iterator_traits<_Iter>::value_type;
  453. return _Cvt<typename remove_cv<__value_type>::type>::
  454. _S_convert(__first, __last);
  455. }
  456. template<typename _InputIterator>
  457. static string_type
  458. _S_convert(_InputIterator __src, __detail::__null_terminated)
  459. {
  460. // Read from iterator into basic_string until a null value is seen:
  461. auto __s = _S_string_from_iter(__src);
  462. // Convert (if needed) from iterator's value type to path::value_type:
  463. return string_type(_S_convert(__s.data(), __s.data() + __s.size()));
  464. }
  465. static string_type
  466. _S_convert_loc(const char* __first, const char* __last,
  467. const std::locale& __loc);
  468. template<typename _Iter>
  469. static string_type
  470. _S_convert_loc(_Iter __first, _Iter __last, const std::locale& __loc)
  471. {
  472. const std::string __str(__first, __last);
  473. return _S_convert_loc(__str.data(), __str.data()+__str.size(), __loc);
  474. }
  475. template<typename _InputIterator>
  476. static string_type
  477. _S_convert_loc(_InputIterator __src, __detail::__null_terminated,
  478. const std::locale& __loc)
  479. {
  480. const std::string __s = _S_string_from_iter(__src);
  481. return _S_convert_loc(__s.data(), __s.data() + __s.size(), __loc);
  482. }
  483. template<typename _CharT, typename _Traits, typename _Allocator>
  484. static basic_string<_CharT, _Traits, _Allocator>
  485. _S_str_convert(basic_string_view<value_type>, const _Allocator&);
  486. void _M_split_cmpts();
  487. _Type _M_type() const noexcept { return _M_cmpts.type(); }
  488. string_type _M_pathname;
  489. struct _Cmpt;
  490. struct _List
  491. {
  492. using value_type = _Cmpt;
  493. using iterator = value_type*;
  494. using const_iterator = const value_type*;
  495. _List();
  496. _List(const _List&);
  497. _List(_List&&) = default;
  498. _List& operator=(const _List&);
  499. _List& operator=(_List&&) = default;
  500. ~_List() = default;
  501. _Type type() const noexcept
  502. { return _Type{reinterpret_cast<uintptr_t>(_M_impl.get()) & 0x3}; }
  503. void type(_Type) noexcept;
  504. int size() const noexcept; // zero unless type() == _Type::_Multi
  505. bool empty() const noexcept; // true unless type() == _Type::_Multi
  506. void clear();
  507. void swap(_List& __l) noexcept { _M_impl.swap(__l._M_impl); }
  508. int capacity() const noexcept;
  509. void reserve(int, bool); ///< @pre type() == _Type::_Multi
  510. // All the member functions below here have a precondition !empty()
  511. // (and they should only be called from within the library).
  512. iterator begin();
  513. iterator end();
  514. const_iterator begin() const;
  515. const_iterator end() const;
  516. value_type& front() noexcept;
  517. value_type& back() noexcept;
  518. const value_type& front() const noexcept;
  519. const value_type& back() const noexcept;
  520. void pop_back();
  521. void _M_erase_from(const_iterator __pos); // erases [__pos,end())
  522. struct _Impl;
  523. struct _Impl_deleter
  524. {
  525. void operator()(_Impl*) const noexcept;
  526. };
  527. unique_ptr<_Impl, _Impl_deleter> _M_impl;
  528. };
  529. _List _M_cmpts;
  530. struct _Parser;
  531. };
  532. /// @relates std::filesystem::path @{
  533. inline void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); }
  534. size_t hash_value(const path& __p) noexcept;
  535. /// @}
  536. /// Exception type thrown by the Filesystem library
  537. class filesystem_error : public std::system_error
  538. {
  539. public:
  540. filesystem_error(const string& __what_arg, error_code __ec);
  541. filesystem_error(const string& __what_arg, const path& __p1,
  542. error_code __ec);
  543. filesystem_error(const string& __what_arg, const path& __p1,
  544. const path& __p2, error_code __ec);
  545. filesystem_error(const filesystem_error&) = default;
  546. filesystem_error& operator=(const filesystem_error&) = default;
  547. // No move constructor or assignment operator.
  548. // Copy rvalues instead, so that _M_impl is not left empty.
  549. ~filesystem_error();
  550. const path& path1() const noexcept;
  551. const path& path2() const noexcept;
  552. const char* what() const noexcept;
  553. private:
  554. struct _Impl;
  555. std::__shared_ptr<const _Impl> _M_impl;
  556. };
  557. /** Create a path from a UTF-8-encoded sequence of char
  558. *
  559. * @relates std::filesystem::path
  560. */
  561. template<typename _InputIterator,
  562. typename _Require = __detail::_Path<_InputIterator, _InputIterator>,
  563. typename _CharT
  564. = __detail::__value_type_is_char_or_char8_t<_InputIterator>>
  565. inline path
  566. u8path(_InputIterator __first, _InputIterator __last)
  567. {
  568. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  569. if constexpr (is_same_v<_CharT, char>)
  570. {
  571. // XXX This assumes native wide encoding is UTF-16.
  572. std::codecvt_utf8_utf16<path::value_type> __cvt;
  573. path::string_type __tmp;
  574. if constexpr (is_pointer_v<_InputIterator>)
  575. {
  576. if (__str_codecvt_in_all(__first, __last, __tmp, __cvt))
  577. return path{ __tmp };
  578. }
  579. else
  580. {
  581. const std::string __u8str{__first, __last};
  582. const char* const __p = __u8str.data();
  583. if (__str_codecvt_in_all(__p, __p + __u8str.size(), __tmp, __cvt))
  584. return path{ __tmp };
  585. }
  586. _GLIBCXX_THROW_OR_ABORT(filesystem_error(
  587. "Cannot convert character sequence",
  588. std::make_error_code(errc::illegal_byte_sequence)));
  589. }
  590. else
  591. return path{ __first, __last };
  592. #else
  593. // This assumes native normal encoding is UTF-8.
  594. return path{ __first, __last };
  595. #endif
  596. }
  597. /** Create a path from a UTF-8-encoded sequence of char
  598. *
  599. * @relates std::filesystem::path
  600. */
  601. template<typename _Source,
  602. typename _Require = __detail::_Path<_Source>,
  603. typename _CharT = __detail::__value_type_is_char_or_char8_t<_Source>>
  604. inline path
  605. u8path(const _Source& __source)
  606. {
  607. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  608. if constexpr (is_same_v<_CharT, char>)
  609. {
  610. if constexpr (is_convertible_v<const _Source&, std::string_view>)
  611. {
  612. const std::string_view __s = __source;
  613. return filesystem::u8path(__s.data(), __s.data() + __s.size());
  614. }
  615. else
  616. {
  617. std::string __s = path::_S_string_from_iter(__source);
  618. return filesystem::u8path(__s.data(), __s.data() + __s.size());
  619. }
  620. }
  621. else
  622. return path{ __source };
  623. #else
  624. return path{ __source };
  625. #endif
  626. }
  627. /// @cond undocumented
  628. struct path::_Cmpt : path
  629. {
  630. _Cmpt(basic_string_view<value_type> __s, _Type __t, size_t __pos)
  631. : path(__s, __t), _M_pos(__pos) { }
  632. _Cmpt() : _M_pos(-1) { }
  633. size_t _M_pos;
  634. };
  635. // specialize _Cvt for degenerate 'noconv' case
  636. template<>
  637. struct path::_Cvt<path::value_type>
  638. {
  639. template<typename _Iter>
  640. static string_type
  641. _S_convert(_Iter __first, _Iter __last)
  642. { return string_type{__first, __last}; }
  643. };
  644. #if !defined _GLIBCXX_FILESYSTEM_IS_WINDOWS && defined _GLIBCXX_USE_CHAR8_T
  645. // For POSIX converting from char8_t to char is also 'noconv'
  646. template<>
  647. struct path::_Cvt<char8_t>
  648. {
  649. template<typename _Iter>
  650. static string_type
  651. _S_convert(_Iter __first, _Iter __last)
  652. { return string_type(__first, __last); }
  653. };
  654. #endif
  655. template<typename _CharT>
  656. struct path::_Cvt
  657. {
  658. static string_type
  659. _S_convert(const _CharT* __f, const _CharT* __l)
  660. {
  661. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  662. std::wstring __wstr;
  663. if constexpr (is_same_v<_CharT, char>)
  664. {
  665. struct _UCvt : std::codecvt<wchar_t, char, std::mbstate_t>
  666. { } __cvt;
  667. if (__str_codecvt_in_all(__f, __l, __wstr, __cvt))
  668. return __wstr;
  669. }
  670. #ifdef _GLIBCXX_USE_CHAR8_T
  671. else if constexpr (is_same_v<_CharT, char8_t>)
  672. {
  673. const char* __f2 = (const char*)__f;
  674. const char* __l2 = (const char*)__l;
  675. std::codecvt_utf8_utf16<wchar_t> __wcvt;
  676. if (__str_codecvt_in_all(__f2, __l2, __wstr, __wcvt))
  677. return __wstr;
  678. }
  679. #endif
  680. else // char16_t or char32_t
  681. {
  682. struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t>
  683. { } __cvt;
  684. std::string __str;
  685. if (__str_codecvt_out_all(__f, __l, __str, __cvt))
  686. {
  687. const char* __f2 = __str.data();
  688. const char* __l2 = __f2 + __str.size();
  689. std::codecvt_utf8_utf16<wchar_t> __wcvt;
  690. if (__str_codecvt_in_all(__f2, __l2, __wstr, __wcvt))
  691. return __wstr;
  692. }
  693. }
  694. #else // ! windows
  695. struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t>
  696. { } __cvt;
  697. std::string __str;
  698. if (__str_codecvt_out_all(__f, __l, __str, __cvt))
  699. return __str;
  700. #endif
  701. _GLIBCXX_THROW_OR_ABORT(filesystem_error(
  702. "Cannot convert character sequence",
  703. std::make_error_code(errc::illegal_byte_sequence)));
  704. }
  705. static string_type
  706. _S_convert(_CharT* __f, _CharT* __l)
  707. {
  708. return _S_convert(const_cast<const _CharT*>(__f),
  709. const_cast<const _CharT*>(__l));
  710. }
  711. template<typename _Iter>
  712. static string_type
  713. _S_convert(_Iter __first, _Iter __last)
  714. {
  715. const std::basic_string<_CharT> __str(__first, __last);
  716. return _S_convert(__str.data(), __str.data() + __str.size());
  717. }
  718. template<typename _Iter, typename _Cont>
  719. static string_type
  720. _S_convert(__gnu_cxx::__normal_iterator<_Iter, _Cont> __first,
  721. __gnu_cxx::__normal_iterator<_Iter, _Cont> __last)
  722. { return _S_convert(__first.base(), __last.base()); }
  723. };
  724. /// @endcond
  725. /// An iterator for the components of a path
  726. class path::iterator
  727. {
  728. public:
  729. using difference_type = std::ptrdiff_t;
  730. using value_type = path;
  731. using reference = const path&;
  732. using pointer = const path*;
  733. using iterator_category = std::bidirectional_iterator_tag;
  734. iterator() : _M_path(nullptr), _M_cur(), _M_at_end() { }
  735. iterator(const iterator&) = default;
  736. iterator& operator=(const iterator&) = default;
  737. reference operator*() const;
  738. pointer operator->() const { return std::__addressof(**this); }
  739. iterator& operator++();
  740. iterator operator++(int) { auto __tmp = *this; ++*this; return __tmp; }
  741. iterator& operator--();
  742. iterator operator--(int) { auto __tmp = *this; --*this; return __tmp; }
  743. friend bool operator==(const iterator& __lhs, const iterator& __rhs)
  744. { return __lhs._M_equals(__rhs); }
  745. friend bool operator!=(const iterator& __lhs, const iterator& __rhs)
  746. { return !__lhs._M_equals(__rhs); }
  747. private:
  748. friend class path;
  749. bool _M_is_multi() const { return _M_path->_M_type() == _Type::_Multi; }
  750. friend difference_type
  751. __path_iter_distance(const iterator& __first, const iterator& __last)
  752. {
  753. __glibcxx_assert(__first._M_path != nullptr);
  754. __glibcxx_assert(__first._M_path == __last._M_path);
  755. if (__first._M_is_multi())
  756. return std::distance(__first._M_cur, __last._M_cur);
  757. else if (__first._M_at_end == __last._M_at_end)
  758. return 0;
  759. else
  760. return __first._M_at_end ? -1 : 1;
  761. }
  762. friend void
  763. __path_iter_advance(iterator& __i, difference_type __n)
  764. {
  765. if (__n == 1)
  766. ++__i;
  767. else if (__n == -1)
  768. --__i;
  769. else if (__n != 0)
  770. {
  771. __glibcxx_assert(__i._M_path != nullptr);
  772. __glibcxx_assert(__i._M_is_multi());
  773. // __glibcxx_assert(__i._M_path->_M_cmpts.end() - __i._M_cur >= __n);
  774. __i._M_cur += __n;
  775. }
  776. }
  777. iterator(const path* __path, path::_List::const_iterator __iter)
  778. : _M_path(__path), _M_cur(__iter), _M_at_end()
  779. { }
  780. iterator(const path* __path, bool __at_end)
  781. : _M_path(__path), _M_cur(), _M_at_end(__at_end)
  782. { }
  783. bool _M_equals(iterator) const;
  784. const path* _M_path;
  785. path::_List::const_iterator _M_cur;
  786. bool _M_at_end; // only used when type != _Multi
  787. };
  788. inline path&
  789. path::operator=(path&& __p) noexcept
  790. {
  791. if (&__p == this) [[__unlikely__]]
  792. return *this;
  793. _M_pathname = std::move(__p._M_pathname);
  794. _M_cmpts = std::move(__p._M_cmpts);
  795. __p.clear();
  796. return *this;
  797. }
  798. inline path&
  799. path::operator=(string_type&& __source)
  800. { return *this = path(std::move(__source)); }
  801. inline path&
  802. path::assign(string_type&& __source)
  803. { return *this = path(std::move(__source)); }
  804. inline path&
  805. path::operator+=(const string_type& __x)
  806. {
  807. _M_concat(__x);
  808. return *this;
  809. }
  810. inline path&
  811. path::operator+=(const value_type* __x)
  812. {
  813. _M_concat(__x);
  814. return *this;
  815. }
  816. inline path&
  817. path::operator+=(value_type __x)
  818. {
  819. _M_concat(basic_string_view<value_type>(&__x, 1));
  820. return *this;
  821. }
  822. inline path&
  823. path::operator+=(basic_string_view<value_type> __x)
  824. {
  825. _M_concat(__x);
  826. return *this;
  827. }
  828. template<typename _CharT>
  829. inline __detail::_Path<_CharT*, _CharT*>&
  830. path::operator+=(_CharT __x)
  831. {
  832. auto* __addr = std::__addressof(__x);
  833. return concat(__addr, __addr + 1);
  834. }
  835. inline path&
  836. path::make_preferred()
  837. {
  838. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  839. std::replace(_M_pathname.begin(), _M_pathname.end(), L'/',
  840. preferred_separator);
  841. #endif
  842. return *this;
  843. }
  844. inline void path::swap(path& __rhs) noexcept
  845. {
  846. _M_pathname.swap(__rhs._M_pathname);
  847. _M_cmpts.swap(__rhs._M_cmpts);
  848. }
  849. /// @cond undocumented
  850. template<typename _CharT, typename _Traits, typename _Allocator>
  851. std::basic_string<_CharT, _Traits, _Allocator>
  852. path::_S_str_convert(basic_string_view<value_type> __str,
  853. const _Allocator& __a)
  854. {
  855. static_assert(!is_same_v<_CharT, value_type>);
  856. using _WString = basic_string<_CharT, _Traits, _Allocator>;
  857. if (__str.size() == 0)
  858. return _WString(__a);
  859. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  860. // First convert native string from UTF-16 to to UTF-8.
  861. // XXX This assumes that the execution wide-character set is UTF-16.
  862. std::codecvt_utf8_utf16<value_type> __cvt;
  863. using _CharAlloc = __alloc_rebind<_Allocator, char>;
  864. using _String = basic_string<char, char_traits<char>, _CharAlloc>;
  865. _String __u8str{_CharAlloc{__a}};
  866. const value_type* __wfirst = __str.data();
  867. const value_type* __wlast = __wfirst + __str.size();
  868. if (__str_codecvt_out_all(__wfirst, __wlast, __u8str, __cvt)) {
  869. if constexpr (is_same_v<_CharT, char>)
  870. return __u8str; // XXX assumes native ordinary encoding is UTF-8.
  871. else {
  872. const char* __first = __u8str.data();
  873. const char* __last = __first + __u8str.size();
  874. #else
  875. const value_type* __first = __str.data();
  876. const value_type* __last = __first + __str.size();
  877. #endif
  878. // Convert UTF-8 string to requested format.
  879. #ifdef _GLIBCXX_USE_CHAR8_T
  880. if constexpr (is_same_v<_CharT, char8_t>)
  881. return _WString(__first, __last, __a);
  882. else
  883. #endif
  884. {
  885. // Convert UTF-8 to wide string.
  886. _WString __wstr(__a);
  887. struct _UCvt : std::codecvt<_CharT, char, std::mbstate_t> { } __cvt;
  888. if (__str_codecvt_in_all(__first, __last, __wstr, __cvt))
  889. return __wstr;
  890. }
  891. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  892. } }
  893. #endif
  894. _GLIBCXX_THROW_OR_ABORT(filesystem_error(
  895. "Cannot convert character sequence",
  896. std::make_error_code(errc::illegal_byte_sequence)));
  897. }
  898. /// @endcond
  899. template<typename _CharT, typename _Traits, typename _Allocator>
  900. inline basic_string<_CharT, _Traits, _Allocator>
  901. path::string(const _Allocator& __a) const
  902. {
  903. if constexpr (is_same_v<_CharT, value_type>)
  904. return { _M_pathname.c_str(), _M_pathname.length(), __a };
  905. else
  906. return _S_str_convert<_CharT, _Traits>(_M_pathname, __a);
  907. }
  908. inline std::string
  909. path::string() const { return string<char>(); }
  910. #if _GLIBCXX_USE_WCHAR_T
  911. inline std::wstring
  912. path::wstring() const { return string<wchar_t>(); }
  913. #endif
  914. #ifdef _GLIBCXX_USE_CHAR8_T
  915. inline std::u8string
  916. path::u8string() const { return string<char8_t>(); }
  917. #else
  918. inline std::string
  919. path::u8string() const
  920. {
  921. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  922. std::string __str;
  923. // convert from native wide encoding (assumed to be UTF-16) to UTF-8
  924. std::codecvt_utf8_utf16<value_type> __cvt;
  925. const value_type* __first = _M_pathname.data();
  926. const value_type* __last = __first + _M_pathname.size();
  927. if (__str_codecvt_out_all(__first, __last, __str, __cvt))
  928. return __str;
  929. _GLIBCXX_THROW_OR_ABORT(filesystem_error(
  930. "Cannot convert character sequence",
  931. std::make_error_code(errc::illegal_byte_sequence)));
  932. #else
  933. return _M_pathname;
  934. #endif
  935. }
  936. #endif // _GLIBCXX_USE_CHAR8_T
  937. inline std::u16string
  938. path::u16string() const { return string<char16_t>(); }
  939. inline std::u32string
  940. path::u32string() const { return string<char32_t>(); }
  941. template<typename _CharT, typename _Traits, typename _Allocator>
  942. inline std::basic_string<_CharT, _Traits, _Allocator>
  943. path::generic_string(const _Allocator& __a) const
  944. {
  945. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  946. const value_type __slash = L'/';
  947. #else
  948. const value_type __slash = '/';
  949. #endif
  950. using _Alloc2 = typename allocator_traits<_Allocator>::template
  951. rebind_alloc<value_type>;
  952. basic_string<value_type, char_traits<value_type>, _Alloc2> __str(__a);
  953. if (_M_type() == _Type::_Root_dir)
  954. __str.assign(1, __slash);
  955. else
  956. {
  957. __str.reserve(_M_pathname.size());
  958. bool __add_slash = false;
  959. for (auto& __elem : *this)
  960. {
  961. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  962. if (__elem._M_type() == _Type::_Root_dir)
  963. {
  964. __str += __slash;
  965. continue;
  966. }
  967. #endif
  968. if (__add_slash)
  969. __str += __slash;
  970. __str += basic_string_view<value_type>(__elem._M_pathname);
  971. __add_slash = __elem._M_type() == _Type::_Filename;
  972. }
  973. }
  974. if constexpr (is_same_v<_CharT, value_type>)
  975. return __str;
  976. else
  977. return _S_str_convert<_CharT, _Traits>(__str, __a);
  978. }
  979. inline std::string
  980. path::generic_string() const
  981. { return generic_string<char>(); }
  982. #if _GLIBCXX_USE_WCHAR_T
  983. inline std::wstring
  984. path::generic_wstring() const
  985. { return generic_string<wchar_t>(); }
  986. #endif
  987. #ifdef _GLIBCXX_USE_CHAR8_T
  988. inline std::u8string
  989. path::generic_u8string() const
  990. { return generic_string<char8_t>(); }
  991. #else
  992. inline std::string
  993. path::generic_u8string() const
  994. { return generic_string(); }
  995. #endif
  996. inline std::u16string
  997. path::generic_u16string() const
  998. { return generic_string<char16_t>(); }
  999. inline std::u32string
  1000. path::generic_u32string() const
  1001. { return generic_string<char32_t>(); }
  1002. inline int
  1003. path::compare(const string_type& __s) const noexcept
  1004. { return compare(basic_string_view<value_type>(__s)); }
  1005. inline int
  1006. path::compare(const value_type* __s) const noexcept
  1007. { return compare(basic_string_view<value_type>(__s)); }
  1008. inline path
  1009. path::filename() const
  1010. {
  1011. if (empty())
  1012. return {};
  1013. else if (_M_type() == _Type::_Filename)
  1014. return *this;
  1015. else if (_M_type() == _Type::_Multi)
  1016. {
  1017. if (_M_pathname.back() == preferred_separator)
  1018. return {};
  1019. auto& __last = *--end();
  1020. if (__last._M_type() == _Type::_Filename)
  1021. return __last;
  1022. }
  1023. return {};
  1024. }
  1025. inline path
  1026. path::stem() const
  1027. {
  1028. auto ext = _M_find_extension();
  1029. if (ext.first && ext.second != 0)
  1030. return path{ext.first->substr(0, ext.second)};
  1031. return {};
  1032. }
  1033. inline path
  1034. path::extension() const
  1035. {
  1036. auto ext = _M_find_extension();
  1037. if (ext.first && ext.second != string_type::npos)
  1038. return path{ext.first->substr(ext.second)};
  1039. return {};
  1040. }
  1041. inline bool
  1042. path::has_stem() const noexcept
  1043. {
  1044. auto ext = _M_find_extension();
  1045. return ext.first && ext.second != 0;
  1046. }
  1047. inline bool
  1048. path::has_extension() const noexcept
  1049. {
  1050. auto ext = _M_find_extension();
  1051. return ext.first && ext.second != string_type::npos;
  1052. }
  1053. inline bool
  1054. path::is_absolute() const noexcept
  1055. {
  1056. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  1057. return has_root_name() && has_root_directory();
  1058. #else
  1059. return has_root_directory();
  1060. #endif
  1061. }
  1062. inline path::iterator
  1063. path::begin() const
  1064. {
  1065. if (_M_type() == _Type::_Multi)
  1066. return iterator(this, _M_cmpts.begin());
  1067. return iterator(this, empty());
  1068. }
  1069. inline path::iterator
  1070. path::end() const
  1071. {
  1072. if (_M_type() == _Type::_Multi)
  1073. return iterator(this, _M_cmpts.end());
  1074. return iterator(this, true);
  1075. }
  1076. inline path::iterator&
  1077. path::iterator::operator++()
  1078. {
  1079. __glibcxx_assert(_M_path != nullptr);
  1080. if (_M_path->_M_type() == _Type::_Multi)
  1081. {
  1082. __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
  1083. ++_M_cur;
  1084. }
  1085. else
  1086. {
  1087. __glibcxx_assert(!_M_at_end);
  1088. _M_at_end = true;
  1089. }
  1090. return *this;
  1091. }
  1092. inline path::iterator&
  1093. path::iterator::operator--()
  1094. {
  1095. __glibcxx_assert(_M_path != nullptr);
  1096. if (_M_path->_M_type() == _Type::_Multi)
  1097. {
  1098. __glibcxx_assert(_M_cur != _M_path->_M_cmpts.begin());
  1099. --_M_cur;
  1100. }
  1101. else
  1102. {
  1103. __glibcxx_assert(_M_at_end);
  1104. _M_at_end = false;
  1105. }
  1106. return *this;
  1107. }
  1108. inline path::iterator::reference
  1109. path::iterator::operator*() const
  1110. {
  1111. __glibcxx_assert(_M_path != nullptr);
  1112. if (_M_path->_M_type() == _Type::_Multi)
  1113. {
  1114. __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
  1115. return *_M_cur;
  1116. }
  1117. return *_M_path;
  1118. }
  1119. inline bool
  1120. path::iterator::_M_equals(iterator __rhs) const
  1121. {
  1122. if (_M_path != __rhs._M_path)
  1123. return false;
  1124. if (_M_path == nullptr)
  1125. return true;
  1126. if (_M_path->_M_type() == path::_Type::_Multi)
  1127. return _M_cur == __rhs._M_cur;
  1128. return _M_at_end == __rhs._M_at_end;
  1129. }
  1130. // @} group filesystem
  1131. _GLIBCXX_END_NAMESPACE_CXX11
  1132. } // namespace filesystem
  1133. inline ptrdiff_t
  1134. distance(filesystem::path::iterator __first, filesystem::path::iterator __last)
  1135. { return __path_iter_distance(__first, __last); }
  1136. template<typename _InputIterator, typename _Distance>
  1137. void
  1138. advance(filesystem::path::iterator& __i, _Distance __n)
  1139. { __path_iter_advance(__i, static_cast<ptrdiff_t>(__n)); }
  1140. extern template class __shared_ptr<const filesystem::filesystem_error::_Impl>;
  1141. _GLIBCXX_END_NAMESPACE_VERSION
  1142. } // namespace std
  1143. #endif // C++17
  1144. #endif // _GLIBCXX_FS_PATH_H