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