fs_path.h 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158
  1. // Class filesystem::path -*- C++ -*-
  2. // Copyright (C) 2014-2018 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 <vector>
  30. #include <locale>
  31. #include <iosfwd>
  32. #include <codecvt>
  33. #include <string_view>
  34. #include <system_error>
  35. #include <bits/stl_algobase.h>
  36. #include <bits/quoted_string.h>
  37. #include <bits/locale_conv.h>
  38. #if defined(_WIN32) && !defined(__CYGWIN__)
  39. # define _GLIBCXX_FILESYSTEM_IS_WINDOWS 1
  40. # include <algorithm>
  41. #endif
  42. namespace std _GLIBCXX_VISIBILITY(default)
  43. {
  44. _GLIBCXX_BEGIN_NAMESPACE_VERSION
  45. namespace filesystem
  46. {
  47. _GLIBCXX_BEGIN_NAMESPACE_CXX11
  48. /**
  49. * @ingroup filesystem
  50. * @{
  51. */
  52. /// A filesystem path.
  53. class path
  54. {
  55. template<typename _CharT>
  56. struct __is_encoded_char : std::false_type { };
  57. template<typename _Iter,
  58. typename _Iter_traits = std::iterator_traits<_Iter>>
  59. using __is_path_iter_src
  60. = __and_<__is_encoded_char<typename _Iter_traits::value_type>,
  61. std::is_base_of<std::input_iterator_tag,
  62. typename _Iter_traits::iterator_category>>;
  63. template<typename _Iter>
  64. static __is_path_iter_src<_Iter>
  65. __is_path_src(_Iter, int);
  66. template<typename _CharT, typename _Traits, typename _Alloc>
  67. static __is_encoded_char<_CharT>
  68. __is_path_src(const basic_string<_CharT, _Traits, _Alloc>&, int);
  69. template<typename _CharT, typename _Traits>
  70. static __is_encoded_char<_CharT>
  71. __is_path_src(const basic_string_view<_CharT, _Traits>&, int);
  72. template<typename _Unknown>
  73. static std::false_type
  74. __is_path_src(const _Unknown&, ...);
  75. template<typename _Tp1, typename _Tp2>
  76. struct __constructible_from;
  77. template<typename _Iter>
  78. struct __constructible_from<_Iter, _Iter>
  79. : __is_path_iter_src<_Iter>
  80. { };
  81. template<typename _Source>
  82. struct __constructible_from<_Source, void>
  83. : decltype(__is_path_src(std::declval<_Source>(), 0))
  84. { };
  85. template<typename _Tp1, typename _Tp2 = void>
  86. using _Path = typename
  87. std::enable_if<__and_<__not_<is_same<remove_cv_t<_Tp1>, path>>,
  88. __not_<is_void<_Tp1>>,
  89. __constructible_from<_Tp1, _Tp2>>::value,
  90. path>::type;
  91. template<typename _Source>
  92. static _Source
  93. _S_range_begin(_Source __begin) { return __begin; }
  94. struct __null_terminated { };
  95. template<typename _Source>
  96. static __null_terminated
  97. _S_range_end(_Source) { return {}; }
  98. template<typename _CharT, typename _Traits, typename _Alloc>
  99. static const _CharT*
  100. _S_range_begin(const basic_string<_CharT, _Traits, _Alloc>& __str)
  101. { return __str.data(); }
  102. template<typename _CharT, typename _Traits, typename _Alloc>
  103. static const _CharT*
  104. _S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str)
  105. { return __str.data() + __str.size(); }
  106. template<typename _CharT, typename _Traits>
  107. static const _CharT*
  108. _S_range_begin(const basic_string_view<_CharT, _Traits>& __str)
  109. { return __str.data(); }
  110. template<typename _CharT, typename _Traits>
  111. static const _CharT*
  112. _S_range_end(const basic_string_view<_CharT, _Traits>& __str)
  113. { return __str.data() + __str.size(); }
  114. template<typename _Tp,
  115. typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())),
  116. typename _Val = typename std::iterator_traits<_Iter>::value_type>
  117. using __value_type_is_char
  118. = typename std::enable_if<std::is_same<_Val, char>::value>::type;
  119. public:
  120. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  121. typedef wchar_t value_type;
  122. static constexpr value_type preferred_separator = L'\\';
  123. #else
  124. typedef char value_type;
  125. static constexpr value_type preferred_separator = '/';
  126. #endif
  127. typedef std::basic_string<value_type> string_type;
  128. enum format { native_format, generic_format, auto_format };
  129. // constructors and destructor
  130. path() noexcept { }
  131. path(const path& __p) = default;
  132. path(path&& __p) noexcept
  133. : _M_pathname(std::move(__p._M_pathname)), _M_type(__p._M_type)
  134. {
  135. _M_split_cmpts();
  136. __p.clear();
  137. }
  138. path(string_type&& __source, format = auto_format)
  139. : _M_pathname(std::move(__source))
  140. { _M_split_cmpts(); }
  141. template<typename _Source,
  142. typename _Require = _Path<_Source>>
  143. path(_Source const& __source, format = auto_format)
  144. : _M_pathname(_S_convert(_S_range_begin(__source),
  145. _S_range_end(__source)))
  146. { _M_split_cmpts(); }
  147. template<typename _InputIterator,
  148. typename _Require = _Path<_InputIterator, _InputIterator>>
  149. path(_InputIterator __first, _InputIterator __last, format = auto_format)
  150. : _M_pathname(_S_convert(__first, __last))
  151. { _M_split_cmpts(); }
  152. template<typename _Source,
  153. typename _Require = _Path<_Source>,
  154. typename _Require2 = __value_type_is_char<_Source>>
  155. path(_Source const& __source, const locale& __loc, format = auto_format)
  156. : _M_pathname(_S_convert_loc(_S_range_begin(__source),
  157. _S_range_end(__source), __loc))
  158. { _M_split_cmpts(); }
  159. template<typename _InputIterator,
  160. typename _Require = _Path<_InputIterator, _InputIterator>,
  161. typename _Require2 = __value_type_is_char<_InputIterator>>
  162. path(_InputIterator __first, _InputIterator __last, const locale& __loc,
  163. format = auto_format)
  164. : _M_pathname(_S_convert_loc(__first, __last, __loc))
  165. { _M_split_cmpts(); }
  166. ~path() = default;
  167. // assignments
  168. path& operator=(const path& __p) = default;
  169. path& operator=(path&& __p) noexcept;
  170. path& operator=(string_type&& __source);
  171. path& assign(string_type&& __source);
  172. template<typename _Source>
  173. _Path<_Source>&
  174. operator=(_Source const& __source)
  175. { return *this = path(__source); }
  176. template<typename _Source>
  177. _Path<_Source>&
  178. assign(_Source const& __source)
  179. { return *this = path(__source); }
  180. template<typename _InputIterator>
  181. _Path<_InputIterator, _InputIterator>&
  182. assign(_InputIterator __first, _InputIterator __last)
  183. { return *this = path(__first, __last); }
  184. // appends
  185. path& operator/=(const path& __p)
  186. {
  187. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  188. if (__p.is_absolute()
  189. || (__p.has_root_name() && __p.root_name() != root_name()))
  190. operator=(__p);
  191. else
  192. {
  193. string_type __pathname;
  194. if (__p.has_root_directory())
  195. __pathname = root_name().native();
  196. else if (has_filename() || (!has_root_directory() && is_absolute()))
  197. __pathname = _M_pathname + preferred_separator;
  198. __pathname += __p.relative_path().native(); // XXX is this right?
  199. _M_pathname.swap(__pathname);
  200. _M_split_cmpts();
  201. }
  202. #else
  203. // Much simpler, as any path with root-name or root-dir is absolute.
  204. if (__p.is_absolute())
  205. operator=(__p);
  206. else
  207. {
  208. if (has_filename() || (_M_type == _Type::_Root_name))
  209. _M_pathname += preferred_separator;
  210. _M_pathname += __p.native();
  211. _M_split_cmpts();
  212. }
  213. #endif
  214. return *this;
  215. }
  216. template <class _Source>
  217. _Path<_Source>&
  218. operator/=(_Source const& __source)
  219. { return _M_append(path(__source)); }
  220. template<typename _Source>
  221. _Path<_Source>&
  222. append(_Source const& __source)
  223. { return _M_append(path(__source)); }
  224. template<typename _InputIterator>
  225. _Path<_InputIterator, _InputIterator>&
  226. append(_InputIterator __first, _InputIterator __last)
  227. { return _M_append(path(__first, __last)); }
  228. // concatenation
  229. path& operator+=(const path& __x);
  230. path& operator+=(const string_type& __x);
  231. path& operator+=(const value_type* __x);
  232. path& operator+=(value_type __x);
  233. path& operator+=(basic_string_view<value_type> __x);
  234. template<typename _Source>
  235. _Path<_Source>&
  236. operator+=(_Source const& __x) { return concat(__x); }
  237. template<typename _CharT>
  238. _Path<_CharT*, _CharT*>&
  239. operator+=(_CharT __x);
  240. template<typename _Source>
  241. _Path<_Source>&
  242. concat(_Source const& __x)
  243. { return *this += _S_convert(_S_range_begin(__x), _S_range_end(__x)); }
  244. template<typename _InputIterator>
  245. _Path<_InputIterator, _InputIterator>&
  246. concat(_InputIterator __first, _InputIterator __last)
  247. { return *this += _S_convert(__first, __last); }
  248. // modifiers
  249. void clear() noexcept { _M_pathname.clear(); _M_split_cmpts(); }
  250. path& make_preferred();
  251. path& remove_filename();
  252. path& replace_filename(const path& __replacement);
  253. path& replace_extension(const path& __replacement = path());
  254. void swap(path& __rhs) noexcept;
  255. // native format observers
  256. const string_type& native() const noexcept { return _M_pathname; }
  257. const value_type* c_str() const noexcept { return _M_pathname.c_str(); }
  258. operator string_type() const { return _M_pathname; }
  259. template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
  260. typename _Allocator = std::allocator<_CharT>>
  261. std::basic_string<_CharT, _Traits, _Allocator>
  262. string(const _Allocator& __a = _Allocator()) const;
  263. std::string string() const;
  264. #if _GLIBCXX_USE_WCHAR_T
  265. std::wstring wstring() const;
  266. #endif
  267. std::string u8string() const;
  268. std::u16string u16string() const;
  269. std::u32string u32string() const;
  270. // generic format observers
  271. template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
  272. typename _Allocator = std::allocator<_CharT>>
  273. std::basic_string<_CharT, _Traits, _Allocator>
  274. generic_string(const _Allocator& __a = _Allocator()) const;
  275. std::string generic_string() const;
  276. #if _GLIBCXX_USE_WCHAR_T
  277. std::wstring generic_wstring() const;
  278. #endif
  279. std::string generic_u8string() const;
  280. std::u16string generic_u16string() const;
  281. std::u32string generic_u32string() const;
  282. // compare
  283. int compare(const path& __p) const noexcept;
  284. int compare(const string_type& __s) const;
  285. int compare(const value_type* __s) const;
  286. int compare(const basic_string_view<value_type> __s) const;
  287. // decomposition
  288. path root_name() const;
  289. path root_directory() const;
  290. path root_path() const;
  291. path relative_path() const;
  292. path parent_path() const;
  293. path filename() const;
  294. path stem() const;
  295. path extension() const;
  296. // query
  297. [[nodiscard]] bool empty() const noexcept { return _M_pathname.empty(); }
  298. bool has_root_name() const;
  299. bool has_root_directory() const;
  300. bool has_root_path() const;
  301. bool has_relative_path() const;
  302. bool has_parent_path() const;
  303. bool has_filename() const;
  304. bool has_stem() const;
  305. bool has_extension() const;
  306. bool is_absolute() const { return has_root_directory(); }
  307. bool is_relative() const { return !is_absolute(); }
  308. // generation
  309. path lexically_normal() const;
  310. path lexically_relative(const path& base) const;
  311. path lexically_proximate(const path& base) const;
  312. // iterators
  313. class iterator;
  314. typedef iterator const_iterator;
  315. iterator begin() const;
  316. iterator end() const;
  317. private:
  318. enum class _Type : unsigned char {
  319. _Multi, _Root_name, _Root_dir, _Filename
  320. };
  321. path(string_type __str, _Type __type) : _M_pathname(__str), _M_type(__type)
  322. {
  323. __glibcxx_assert(_M_type != _Type::_Multi);
  324. }
  325. enum class _Split { _Stem, _Extension };
  326. path&
  327. _M_append(path __p)
  328. {
  329. if (__p.is_absolute())
  330. operator=(std::move(__p));
  331. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  332. else if (__p.has_root_name() && __p.root_name() != root_name())
  333. operator=(std::move(__p));
  334. #endif
  335. else
  336. operator/=(const_cast<const path&>(__p));
  337. return *this;
  338. }
  339. pair<const string_type*, size_t> _M_find_extension() const;
  340. template<typename _CharT>
  341. struct _Cvt;
  342. static string_type
  343. _S_convert(value_type* __src, __null_terminated)
  344. { return string_type(__src); }
  345. static string_type
  346. _S_convert(const value_type* __src, __null_terminated)
  347. { return string_type(__src); }
  348. template<typename _Iter>
  349. static string_type
  350. _S_convert(_Iter __first, _Iter __last)
  351. {
  352. using __value_type = typename std::iterator_traits<_Iter>::value_type;
  353. return _Cvt<typename remove_cv<__value_type>::type>::
  354. _S_convert(__first, __last);
  355. }
  356. template<typename _InputIterator>
  357. static string_type
  358. _S_convert(_InputIterator __src, __null_terminated)
  359. {
  360. using _Tp = typename std::iterator_traits<_InputIterator>::value_type;
  361. std::basic_string<typename remove_cv<_Tp>::type> __tmp;
  362. for (; *__src != _Tp{}; ++__src)
  363. __tmp.push_back(*__src);
  364. return _S_convert(__tmp.c_str(), __tmp.c_str() + __tmp.size());
  365. }
  366. static string_type
  367. _S_convert_loc(const char* __first, const char* __last,
  368. const std::locale& __loc);
  369. template<typename _Iter>
  370. static string_type
  371. _S_convert_loc(_Iter __first, _Iter __last, const std::locale& __loc)
  372. {
  373. const std::string __str(__first, __last);
  374. return _S_convert_loc(__str.data(), __str.data()+__str.size(), __loc);
  375. }
  376. template<typename _InputIterator>
  377. static string_type
  378. _S_convert_loc(_InputIterator __src, __null_terminated,
  379. const std::locale& __loc)
  380. {
  381. std::string __tmp;
  382. while (*__src != '\0')
  383. __tmp.push_back(*__src++);
  384. return _S_convert_loc(__tmp.data(), __tmp.data()+__tmp.size(), __loc);
  385. }
  386. template<typename _CharT, typename _Traits, typename _Allocator>
  387. static basic_string<_CharT, _Traits, _Allocator>
  388. _S_str_convert(const string_type&, const _Allocator& __a);
  389. bool _S_is_dir_sep(value_type __ch)
  390. {
  391. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  392. return __ch == L'/' || __ch == preferred_separator;
  393. #else
  394. return __ch == '/';
  395. #endif
  396. }
  397. void _M_split_cmpts();
  398. void _M_trim();
  399. void _M_add_root_name(size_t __n);
  400. void _M_add_root_dir(size_t __pos);
  401. void _M_add_filename(size_t __pos, size_t __n);
  402. string_type _M_pathname;
  403. struct _Cmpt;
  404. using _List = _GLIBCXX_STD_C::vector<_Cmpt>;
  405. _List _M_cmpts; // empty unless _M_type == _Type::_Multi
  406. _Type _M_type = _Type::_Filename;
  407. };
  408. template<>
  409. struct path::__is_encoded_char<char> : std::true_type
  410. { using value_type = char; };
  411. template<>
  412. struct path::__is_encoded_char<wchar_t> : std::true_type
  413. { using value_type = wchar_t; };
  414. template<>
  415. struct path::__is_encoded_char<char16_t> : std::true_type
  416. { using value_type = char16_t; };
  417. template<>
  418. struct path::__is_encoded_char<char32_t> : std::true_type
  419. { using value_type = char32_t; };
  420. template<typename _Tp>
  421. struct path::__is_encoded_char<const _Tp> : __is_encoded_char<_Tp> { };
  422. inline void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); }
  423. size_t hash_value(const path& __p) noexcept;
  424. /// Compare paths
  425. inline bool operator<(const path& __lhs, const path& __rhs) noexcept
  426. { return __lhs.compare(__rhs) < 0; }
  427. /// Compare paths
  428. inline bool operator<=(const path& __lhs, const path& __rhs) noexcept
  429. { return !(__rhs < __lhs); }
  430. /// Compare paths
  431. inline bool operator>(const path& __lhs, const path& __rhs) noexcept
  432. { return __rhs < __lhs; }
  433. /// Compare paths
  434. inline bool operator>=(const path& __lhs, const path& __rhs) noexcept
  435. { return !(__lhs < __rhs); }
  436. /// Compare paths
  437. inline bool operator==(const path& __lhs, const path& __rhs) noexcept
  438. { return __lhs.compare(__rhs) == 0; }
  439. /// Compare paths
  440. inline bool operator!=(const path& __lhs, const path& __rhs) noexcept
  441. { return !(__lhs == __rhs); }
  442. /// Append one path to another
  443. inline path operator/(const path& __lhs, const path& __rhs)
  444. {
  445. path __result(__lhs);
  446. __result /= __rhs;
  447. return __result;
  448. }
  449. /// Write a path to a stream
  450. template<typename _CharT, typename _Traits>
  451. basic_ostream<_CharT, _Traits>&
  452. operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p)
  453. {
  454. auto __tmp = __p.string<_CharT, _Traits>();
  455. using __quoted_string
  456. = std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
  457. __os << __quoted_string{__tmp, '"', '\\'};
  458. return __os;
  459. }
  460. /// Read a path from a stream
  461. template<typename _CharT, typename _Traits>
  462. basic_istream<_CharT, _Traits>&
  463. operator>>(basic_istream<_CharT, _Traits>& __is, path& __p)
  464. {
  465. basic_string<_CharT, _Traits> __tmp;
  466. using __quoted_string
  467. = std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
  468. if (__is >> __quoted_string{ __tmp, '"', '\\' })
  469. __p = std::move(__tmp);
  470. return __is;
  471. }
  472. template<typename _Source>
  473. inline auto
  474. u8path(const _Source& __source)
  475. -> decltype(filesystem::path(__source, std::locale::classic()))
  476. {
  477. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  478. const std::string __u8str{__source};
  479. return std::filesystem::u8path(__u8str.begin(), __u8str.end());
  480. #else
  481. return path{ __source };
  482. #endif
  483. }
  484. template<typename _InputIterator>
  485. inline auto
  486. u8path(_InputIterator __first, _InputIterator __last)
  487. -> decltype(filesystem::path(__first, __last, std::locale::classic()))
  488. {
  489. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  490. codecvt_utf8<value_type> __cvt;
  491. string_type __tmp;
  492. if (__str_codecvt_in(__first, __last, __tmp, __cvt))
  493. return path{ __tmp };
  494. else
  495. return {};
  496. #else
  497. return path{ __first, __last };
  498. #endif
  499. }
  500. class filesystem_error : public std::system_error
  501. {
  502. public:
  503. filesystem_error(const string& __what_arg, error_code __ec)
  504. : system_error(__ec, __what_arg) { }
  505. filesystem_error(const string& __what_arg, const path& __p1,
  506. error_code __ec)
  507. : system_error(__ec, __what_arg), _M_path1(__p1) { }
  508. filesystem_error(const string& __what_arg, const path& __p1,
  509. const path& __p2, error_code __ec)
  510. : system_error(__ec, __what_arg), _M_path1(__p1), _M_path2(__p2)
  511. { }
  512. ~filesystem_error();
  513. const path& path1() const noexcept { return _M_path1; }
  514. const path& path2() const noexcept { return _M_path2; }
  515. const char* what() const noexcept { return _M_what.c_str(); }
  516. private:
  517. std::string _M_gen_what();
  518. path _M_path1;
  519. path _M_path2;
  520. std::string _M_what = _M_gen_what();
  521. };
  522. struct path::_Cmpt : path
  523. {
  524. _Cmpt(string_type __s, _Type __t, size_t __pos)
  525. : path(std::move(__s), __t), _M_pos(__pos) { }
  526. _Cmpt() : _M_pos(-1) { }
  527. size_t _M_pos;
  528. };
  529. // specialize _Cvt for degenerate 'noconv' case
  530. template<>
  531. struct path::_Cvt<path::value_type>
  532. {
  533. template<typename _Iter>
  534. static string_type
  535. _S_convert(_Iter __first, _Iter __last)
  536. { return string_type{__first, __last}; }
  537. };
  538. template<typename _CharT>
  539. struct path::_Cvt
  540. {
  541. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  542. static string_type
  543. _S_wconvert(const char* __f, const char* __l, true_type)
  544. {
  545. using _Cvt = std::codecvt<wchar_t, char, mbstate_t>;
  546. const auto& __cvt = std::use_facet<_Cvt>(std::locale{});
  547. std::wstring __wstr;
  548. if (__str_codecvt_in(__f, __l, __wstr, __cvt))
  549. return __wstr;
  550. _GLIBCXX_THROW_OR_ABORT(filesystem_error(
  551. "Cannot convert character sequence",
  552. std::make_error_code(errc::illegal_byte_sequence)));
  553. }
  554. static string_type
  555. _S_wconvert(const _CharT* __f, const _CharT* __l, false_type)
  556. {
  557. std::codecvt_utf8<_CharT> __cvt;
  558. std::string __str;
  559. if (__str_codecvt_out(__f, __l, __str, __cvt))
  560. {
  561. const char* __f2 = __str.data();
  562. const char* __l2 = __f2 + __str.size();
  563. std::codecvt_utf8<wchar_t> __wcvt;
  564. std::wstring __wstr;
  565. if (__str_codecvt_in(__f2, __l2, __wstr, __wcvt))
  566. return __wstr;
  567. }
  568. _GLIBCXX_THROW_OR_ABORT(filesystem_error(
  569. "Cannot convert character sequence",
  570. std::make_error_code(errc::illegal_byte_sequence)));
  571. }
  572. static string_type
  573. _S_convert(const _CharT* __f, const _CharT* __l)
  574. {
  575. return _S_wconvert(__f, __l, is_same<_CharT, char>{});
  576. }
  577. #else
  578. static string_type
  579. _S_convert(const _CharT* __f, const _CharT* __l)
  580. {
  581. std::codecvt_utf8<_CharT> __cvt;
  582. std::string __str;
  583. if (__str_codecvt_out(__f, __l, __str, __cvt))
  584. return __str;
  585. _GLIBCXX_THROW_OR_ABORT(filesystem_error(
  586. "Cannot convert character sequence",
  587. std::make_error_code(errc::illegal_byte_sequence)));
  588. }
  589. #endif
  590. static string_type
  591. _S_convert(_CharT* __f, _CharT* __l)
  592. {
  593. return _S_convert(const_cast<const _CharT*>(__f),
  594. const_cast<const _CharT*>(__l));
  595. }
  596. template<typename _Iter>
  597. static string_type
  598. _S_convert(_Iter __first, _Iter __last)
  599. {
  600. const std::basic_string<_CharT> __str(__first, __last);
  601. return _S_convert(__str.data(), __str.data() + __str.size());
  602. }
  603. template<typename _Iter, typename _Cont>
  604. static string_type
  605. _S_convert(__gnu_cxx::__normal_iterator<_Iter, _Cont> __first,
  606. __gnu_cxx::__normal_iterator<_Iter, _Cont> __last)
  607. { return _S_convert(__first.base(), __last.base()); }
  608. };
  609. /// An iterator for the components of a path
  610. class path::iterator
  611. {
  612. public:
  613. using difference_type = std::ptrdiff_t;
  614. using value_type = path;
  615. using reference = const path&;
  616. using pointer = const path*;
  617. using iterator_category = std::bidirectional_iterator_tag;
  618. iterator() : _M_path(nullptr), _M_cur(), _M_at_end() { }
  619. iterator(const iterator&) = default;
  620. iterator& operator=(const iterator&) = default;
  621. reference operator*() const;
  622. pointer operator->() const { return std::__addressof(**this); }
  623. iterator& operator++();
  624. iterator operator++(int) { auto __tmp = *this; ++*this; return __tmp; }
  625. iterator& operator--();
  626. iterator operator--(int) { auto __tmp = *this; --*this; return __tmp; }
  627. friend bool operator==(const iterator& __lhs, const iterator& __rhs)
  628. { return __lhs._M_equals(__rhs); }
  629. friend bool operator!=(const iterator& __lhs, const iterator& __rhs)
  630. { return !__lhs._M_equals(__rhs); }
  631. private:
  632. friend class path;
  633. iterator(const path* __path, path::_List::const_iterator __iter)
  634. : _M_path(__path), _M_cur(__iter), _M_at_end()
  635. { }
  636. iterator(const path* __path, bool __at_end)
  637. : _M_path(__path), _M_cur(), _M_at_end(__at_end)
  638. { }
  639. bool _M_equals(iterator) const;
  640. const path* _M_path;
  641. path::_List::const_iterator _M_cur;
  642. bool _M_at_end; // only used when type != _Multi
  643. };
  644. inline path&
  645. path::operator=(path&& __p) noexcept
  646. {
  647. _M_pathname = std::move(__p._M_pathname);
  648. _M_cmpts = std::move(__p._M_cmpts);
  649. _M_type = __p._M_type;
  650. __p.clear();
  651. return *this;
  652. }
  653. inline path&
  654. path::operator=(string_type&& __source)
  655. { return *this = path(std::move(__source)); }
  656. inline path&
  657. path::assign(string_type&& __source)
  658. { return *this = path(std::move(__source)); }
  659. inline path&
  660. path::operator+=(const path& __p)
  661. {
  662. return operator+=(__p.native());
  663. }
  664. inline path&
  665. path::operator+=(const string_type& __x)
  666. {
  667. _M_pathname += __x;
  668. _M_split_cmpts();
  669. return *this;
  670. }
  671. inline path&
  672. path::operator+=(const value_type* __x)
  673. {
  674. _M_pathname += __x;
  675. _M_split_cmpts();
  676. return *this;
  677. }
  678. inline path&
  679. path::operator+=(value_type __x)
  680. {
  681. _M_pathname += __x;
  682. _M_split_cmpts();
  683. return *this;
  684. }
  685. inline path&
  686. path::operator+=(basic_string_view<value_type> __x)
  687. {
  688. _M_pathname.append(__x.data(), __x.size());
  689. _M_split_cmpts();
  690. return *this;
  691. }
  692. template<typename _CharT>
  693. inline path::_Path<_CharT*, _CharT*>&
  694. path::operator+=(_CharT __x)
  695. {
  696. auto* __addr = std::__addressof(__x);
  697. return concat(__addr, __addr + 1);
  698. }
  699. inline path&
  700. path::make_preferred()
  701. {
  702. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  703. std::replace(_M_pathname.begin(), _M_pathname.end(), L'/',
  704. preferred_separator);
  705. #endif
  706. return *this;
  707. }
  708. inline void path::swap(path& __rhs) noexcept
  709. {
  710. _M_pathname.swap(__rhs._M_pathname);
  711. _M_cmpts.swap(__rhs._M_cmpts);
  712. std::swap(_M_type, __rhs._M_type);
  713. }
  714. template<typename _CharT, typename _Traits, typename _Allocator>
  715. std::basic_string<_CharT, _Traits, _Allocator>
  716. path::_S_str_convert(const string_type& __str, const _Allocator& __a)
  717. {
  718. if (__str.size() == 0)
  719. return std::basic_string<_CharT, _Traits, _Allocator>(__a);
  720. const value_type* __first = __str.data();
  721. const value_type* __last = __first + __str.size();
  722. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  723. using _CharAlloc = __alloc_rebind<_Allocator, char>;
  724. using _String = basic_string<char, char_traits<char>, _CharAlloc>;
  725. using _WString = basic_string<_CharT, _Traits, _Allocator>;
  726. // use codecvt_utf8<wchar_t> to convert native string to UTF-8
  727. codecvt_utf8<value_type> __cvt;
  728. _String __u8str{_CharAlloc{__a}};
  729. if (__str_codecvt_out(__first, __last, __u8str, __cvt))
  730. {
  731. if constexpr (is_same_v<_CharT, char>)
  732. return __u8str;
  733. else
  734. {
  735. _WString __wstr;
  736. // use codecvt_utf8<_CharT> to convert UTF-8 to wide string
  737. codecvt_utf8<_CharT> __cvt;
  738. const char* __f = __u8str.data();
  739. const char* __l = __f + __u8str.size();
  740. if (__str_codecvt_in(__f, __l, __wstr, __cvt))
  741. return __wstr;
  742. }
  743. }
  744. #else
  745. codecvt_utf8<_CharT> __cvt;
  746. basic_string<_CharT, _Traits, _Allocator> __wstr{__a};
  747. if (__str_codecvt_in(__first, __last, __wstr, __cvt))
  748. return __wstr;
  749. #endif
  750. _GLIBCXX_THROW_OR_ABORT(filesystem_error(
  751. "Cannot convert character sequence",
  752. std::make_error_code(errc::illegal_byte_sequence)));
  753. }
  754. template<typename _CharT, typename _Traits, typename _Allocator>
  755. inline basic_string<_CharT, _Traits, _Allocator>
  756. path::string(const _Allocator& __a) const
  757. {
  758. if constexpr (is_same_v<_CharT, value_type>)
  759. #if _GLIBCXX_USE_CXX11_ABI
  760. return { _M_pathname, __a };
  761. #else
  762. return { _M_pathname, string_type::size_type(0), __a };
  763. #endif
  764. else
  765. return _S_str_convert<_CharT, _Traits>(_M_pathname, __a);
  766. }
  767. inline std::string
  768. path::string() const { return string<char>(); }
  769. #if _GLIBCXX_USE_WCHAR_T
  770. inline std::wstring
  771. path::wstring() const { return string<wchar_t>(); }
  772. #endif
  773. inline std::string
  774. path::u8string() const
  775. {
  776. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  777. std::string __str;
  778. // convert from native encoding to UTF-8
  779. codecvt_utf8<value_type> __cvt;
  780. const value_type* __first = _M_pathname.data();
  781. const value_type* __last = __first + _M_pathname.size();
  782. if (__str_codecvt_out(__first, __last, __str, __cvt))
  783. return __str;
  784. _GLIBCXX_THROW_OR_ABORT(filesystem_error(
  785. "Cannot convert character sequence",
  786. std::make_error_code(errc::illegal_byte_sequence)));
  787. #else
  788. return _M_pathname;
  789. #endif
  790. }
  791. inline std::u16string
  792. path::u16string() const { return string<char16_t>(); }
  793. inline std::u32string
  794. path::u32string() const { return string<char32_t>(); }
  795. template<typename _CharT, typename _Traits, typename _Allocator>
  796. inline std::basic_string<_CharT, _Traits, _Allocator>
  797. path::generic_string(const _Allocator& __a) const
  798. {
  799. #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
  800. const value_type __slash = L'/';
  801. #else
  802. const value_type __slash = '/';
  803. #endif
  804. string_type __str(__a);
  805. if (_M_type == _Type::_Root_dir)
  806. __str.assign(1, __slash);
  807. else
  808. {
  809. __str.reserve(_M_pathname.size());
  810. bool __add_slash = false;
  811. for (auto& __elem : *this)
  812. {
  813. if (__add_slash)
  814. __str += __slash;
  815. __str += __elem._M_pathname;
  816. __add_slash = __elem._M_type == _Type::_Filename;
  817. }
  818. }
  819. if constexpr (is_same_v<_CharT, value_type>)
  820. return __str;
  821. else
  822. return _S_str_convert<_CharT, _Traits>(__str, __a);
  823. }
  824. inline std::string
  825. path::generic_string() const
  826. { return generic_string<char>(); }
  827. #if _GLIBCXX_USE_WCHAR_T
  828. inline std::wstring
  829. path::generic_wstring() const
  830. { return generic_string<wchar_t>(); }
  831. #endif
  832. inline std::string
  833. path::generic_u8string() const
  834. { return generic_string(); }
  835. inline std::u16string
  836. path::generic_u16string() const
  837. { return generic_string<char16_t>(); }
  838. inline std::u32string
  839. path::generic_u32string() const
  840. { return generic_string<char32_t>(); }
  841. inline int
  842. path::compare(const string_type& __s) const { return compare(path(__s)); }
  843. inline int
  844. path::compare(const value_type* __s) const { return compare(path(__s)); }
  845. inline int
  846. path::compare(basic_string_view<value_type> __s) const
  847. { return compare(path(__s)); }
  848. inline path
  849. path::filename() const
  850. {
  851. if (empty())
  852. return {};
  853. else if (_M_type == _Type::_Filename)
  854. return *this;
  855. else if (_M_type == _Type::_Multi)
  856. {
  857. if (_M_pathname.back() == preferred_separator)
  858. return {};
  859. auto& __last = *--end();
  860. if (__last._M_type == _Type::_Filename)
  861. return __last;
  862. }
  863. return {};
  864. }
  865. inline path
  866. path::stem() const
  867. {
  868. auto ext = _M_find_extension();
  869. if (ext.first && ext.second != 0)
  870. return path{ext.first->substr(0, ext.second)};
  871. return {};
  872. }
  873. inline path
  874. path::extension() const
  875. {
  876. auto ext = _M_find_extension();
  877. if (ext.first && ext.second != string_type::npos)
  878. return path{ext.first->substr(ext.second)};
  879. return {};
  880. }
  881. inline bool
  882. path::has_stem() const
  883. {
  884. auto ext = _M_find_extension();
  885. return ext.first && ext.second != 0;
  886. }
  887. inline bool
  888. path::has_extension() const
  889. {
  890. auto ext = _M_find_extension();
  891. return ext.first && ext.second != string_type::npos;
  892. }
  893. inline path::iterator
  894. path::begin() const
  895. {
  896. if (_M_type == _Type::_Multi)
  897. return iterator(this, _M_cmpts.begin());
  898. return iterator(this, empty());
  899. }
  900. inline path::iterator
  901. path::end() const
  902. {
  903. if (_M_type == _Type::_Multi)
  904. return iterator(this, _M_cmpts.end());
  905. return iterator(this, true);
  906. }
  907. inline path::iterator&
  908. path::iterator::operator++()
  909. {
  910. __glibcxx_assert(_M_path != nullptr);
  911. if (_M_path->_M_type == _Type::_Multi)
  912. {
  913. __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
  914. ++_M_cur;
  915. }
  916. else
  917. {
  918. __glibcxx_assert(!_M_at_end);
  919. _M_at_end = true;
  920. }
  921. return *this;
  922. }
  923. inline path::iterator&
  924. path::iterator::operator--()
  925. {
  926. __glibcxx_assert(_M_path != nullptr);
  927. if (_M_path->_M_type == _Type::_Multi)
  928. {
  929. __glibcxx_assert(_M_cur != _M_path->_M_cmpts.begin());
  930. --_M_cur;
  931. }
  932. else
  933. {
  934. __glibcxx_assert(_M_at_end);
  935. _M_at_end = false;
  936. }
  937. return *this;
  938. }
  939. inline path::iterator::reference
  940. path::iterator::operator*() const
  941. {
  942. __glibcxx_assert(_M_path != nullptr);
  943. if (_M_path->_M_type == _Type::_Multi)
  944. {
  945. __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
  946. return *_M_cur;
  947. }
  948. return *_M_path;
  949. }
  950. inline bool
  951. path::iterator::_M_equals(iterator __rhs) const
  952. {
  953. if (_M_path != __rhs._M_path)
  954. return false;
  955. if (_M_path == nullptr)
  956. return true;
  957. if (_M_path->_M_type == path::_Type::_Multi)
  958. return _M_cur == __rhs._M_cur;
  959. return _M_at_end == __rhs._M_at_end;
  960. }
  961. // @} group filesystem
  962. _GLIBCXX_END_NAMESPACE_CXX11
  963. } // namespace filesystem
  964. _GLIBCXX_END_NAMESPACE_VERSION
  965. } // namespace std
  966. #endif // C++17
  967. #endif // _GLIBCXX_FS_PATH_H