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