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