libstdc++
|
00001 // Class filesystem::path -*- C++ -*- 00002 00003 // Copyright (C) 2014-2018 Free Software Foundation, Inc. 00004 // 00005 // This file is part of the GNU ISO C++ Library. This library is free 00006 // software; you can redistribute it and/or modify it under the 00007 // terms of the GNU General Public License as published by the 00008 // Free Software Foundation; either version 3, or (at your option) 00009 // any later version. 00010 00011 // This library is distributed in the hope that it will be useful, 00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 // GNU General Public License for more details. 00015 00016 // Under Section 7 of GPL version 3, you are granted additional 00017 // permissions described in the GCC Runtime Library Exception, version 00018 // 3.1, as published by the Free Software Foundation. 00019 00020 // You should have received a copy of the GNU General Public License and 00021 // a copy of the GCC Runtime Library Exception along with this program; 00022 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 00023 // <http://www.gnu.org/licenses/>. 00024 00025 /** @file include/bits/fs_path.h 00026 * This is an internal header file, included by other library headers. 00027 * Do not attempt to use it directly. @headername{filesystem} 00028 */ 00029 00030 #ifndef _GLIBCXX_FS_PATH_H 00031 #define _GLIBCXX_FS_PATH_H 1 00032 00033 #if __cplusplus >= 201703L 00034 00035 #include <utility> 00036 #include <type_traits> 00037 #include <vector> 00038 #include <locale> 00039 #include <iosfwd> 00040 #include <codecvt> 00041 #include <string_view> 00042 #include <system_error> 00043 #include <bits/stl_algobase.h> 00044 #include <bits/quoted_string.h> 00045 #include <bits/locale_conv.h> 00046 00047 #if defined(_WIN32) && !defined(__CYGWIN__) 00048 # define _GLIBCXX_FILESYSTEM_IS_WINDOWS 1 00049 # include <algorithm> 00050 #endif 00051 00052 namespace std _GLIBCXX_VISIBILITY(default) 00053 { 00054 _GLIBCXX_BEGIN_NAMESPACE_VERSION 00055 00056 namespace filesystem 00057 { 00058 _GLIBCXX_BEGIN_NAMESPACE_CXX11 00059 00060 /** 00061 * @ingroup filesystem 00062 * @{ 00063 */ 00064 00065 /// A filesystem path. 00066 class path 00067 { 00068 template<typename _CharT> 00069 struct __is_encoded_char : std::false_type { }; 00070 00071 template<typename _Iter, 00072 typename _Iter_traits = std::iterator_traits<_Iter>> 00073 using __is_path_iter_src 00074 = __and_<__is_encoded_char<typename _Iter_traits::value_type>, 00075 std::is_base_of<std::input_iterator_tag, 00076 typename _Iter_traits::iterator_category>>; 00077 00078 template<typename _Iter> 00079 static __is_path_iter_src<_Iter> 00080 __is_path_src(_Iter, int); 00081 00082 template<typename _CharT, typename _Traits, typename _Alloc> 00083 static __is_encoded_char<_CharT> 00084 __is_path_src(const basic_string<_CharT, _Traits, _Alloc>&, int); 00085 00086 template<typename _CharT, typename _Traits> 00087 static __is_encoded_char<_CharT> 00088 __is_path_src(const basic_string_view<_CharT, _Traits>&, int); 00089 00090 template<typename _Unknown> 00091 static std::false_type 00092 __is_path_src(const _Unknown&, ...); 00093 00094 template<typename _Tp1, typename _Tp2> 00095 struct __constructible_from; 00096 00097 template<typename _Iter> 00098 struct __constructible_from<_Iter, _Iter> 00099 : __is_path_iter_src<_Iter> 00100 { }; 00101 00102 template<typename _Source> 00103 struct __constructible_from<_Source, void> 00104 : decltype(__is_path_src(std::declval<_Source>(), 0)) 00105 { }; 00106 00107 template<typename _Tp1, typename _Tp2 = void> 00108 using _Path = typename 00109 std::enable_if<__and_<__not_<is_same<_Tp1, path>>, 00110 __constructible_from<_Tp1, _Tp2>>::value, 00111 path>::type; 00112 00113 template<typename _Source> 00114 static _Source 00115 _S_range_begin(_Source __begin) { return __begin; } 00116 00117 struct __null_terminated { }; 00118 00119 template<typename _Source> 00120 static __null_terminated 00121 _S_range_end(_Source) { return {}; } 00122 00123 template<typename _CharT, typename _Traits, typename _Alloc> 00124 static const _CharT* 00125 _S_range_begin(const basic_string<_CharT, _Traits, _Alloc>& __str) 00126 { return __str.data(); } 00127 00128 template<typename _CharT, typename _Traits, typename _Alloc> 00129 static const _CharT* 00130 _S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str) 00131 { return __str.data() + __str.size(); } 00132 00133 template<typename _CharT, typename _Traits> 00134 static const _CharT* 00135 _S_range_begin(const basic_string_view<_CharT, _Traits>& __str) 00136 { return __str.data(); } 00137 00138 template<typename _CharT, typename _Traits> 00139 static const _CharT* 00140 _S_range_end(const basic_string_view<_CharT, _Traits>& __str) 00141 { return __str.data() + __str.size(); } 00142 00143 template<typename _Tp, 00144 typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())), 00145 typename _Val = typename std::iterator_traits<_Iter>::value_type> 00146 using __value_type_is_char 00147 = typename std::enable_if<std::is_same<_Val, char>::value>::type; 00148 00149 public: 00150 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00151 typedef wchar_t value_type; 00152 static constexpr value_type preferred_separator = L'\\'; 00153 #else 00154 typedef char value_type; 00155 static constexpr value_type preferred_separator = '/'; 00156 #endif 00157 typedef std::basic_string<value_type> string_type; 00158 00159 enum format { native_format, generic_format, auto_format }; 00160 00161 // constructors and destructor 00162 00163 path() noexcept { } 00164 00165 path(const path& __p) = default; 00166 00167 path(path&& __p) noexcept 00168 : _M_pathname(std::move(__p._M_pathname)), _M_type(__p._M_type) 00169 { 00170 _M_split_cmpts(); 00171 __p.clear(); 00172 } 00173 00174 path(string_type&& __source, format = auto_format) 00175 : _M_pathname(std::move(__source)) 00176 { _M_split_cmpts(); } 00177 00178 template<typename _Source, 00179 typename _Require = _Path<_Source>> 00180 path(_Source const& __source, format = auto_format) 00181 : _M_pathname(_S_convert(_S_range_begin(__source), 00182 _S_range_end(__source))) 00183 { _M_split_cmpts(); } 00184 00185 template<typename _InputIterator, 00186 typename _Require = _Path<_InputIterator, _InputIterator>> 00187 path(_InputIterator __first, _InputIterator __last, format = auto_format) 00188 : _M_pathname(_S_convert(__first, __last)) 00189 { _M_split_cmpts(); } 00190 00191 template<typename _Source, 00192 typename _Require = _Path<_Source>, 00193 typename _Require2 = __value_type_is_char<_Source>> 00194 path(_Source const& __source, const locale& __loc, format = auto_format) 00195 : _M_pathname(_S_convert_loc(_S_range_begin(__source), 00196 _S_range_end(__source), __loc)) 00197 { _M_split_cmpts(); } 00198 00199 template<typename _InputIterator, 00200 typename _Require = _Path<_InputIterator, _InputIterator>, 00201 typename _Require2 = __value_type_is_char<_InputIterator>> 00202 path(_InputIterator __first, _InputIterator __last, const locale& __loc, 00203 format = auto_format) 00204 : _M_pathname(_S_convert_loc(__first, __last, __loc)) 00205 { _M_split_cmpts(); } 00206 00207 ~path() = default; 00208 00209 // assignments 00210 00211 path& operator=(const path& __p) = default; 00212 path& operator=(path&& __p) noexcept; 00213 path& operator=(string_type&& __source); 00214 path& assign(string_type&& __source); 00215 00216 template<typename _Source> 00217 _Path<_Source>& 00218 operator=(_Source const& __source) 00219 { return *this = path(__source); } 00220 00221 template<typename _Source> 00222 _Path<_Source>& 00223 assign(_Source const& __source) 00224 { return *this = path(__source); } 00225 00226 template<typename _InputIterator> 00227 _Path<_InputIterator, _InputIterator>& 00228 assign(_InputIterator __first, _InputIterator __last) 00229 { return *this = path(__first, __last); } 00230 00231 // appends 00232 00233 path& operator/=(const path& __p) 00234 { 00235 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00236 if (__p.is_absolute() 00237 || (__p.has_root_name() && __p.root_name() != root_name())) 00238 operator=(__p); 00239 else 00240 { 00241 string_type __pathname; 00242 if (__p.has_root_directory()) 00243 __pathname = root_name().native(); 00244 else if (has_filename() || (!has_root_directory() && is_absolute())) 00245 __pathname = _M_pathname + preferred_separator; 00246 __pathname += __p.relative_path().native(); // XXX is this right? 00247 _M_pathname.swap(__pathname); 00248 _M_split_cmpts(); 00249 } 00250 #else 00251 // Much simpler, as any path with root-name or root-dir is absolute. 00252 if (__p.is_absolute()) 00253 operator=(__p); 00254 else 00255 { 00256 if (has_filename() || (_M_type == _Type::_Root_name)) 00257 _M_pathname += preferred_separator; 00258 _M_pathname += __p.native(); 00259 _M_split_cmpts(); 00260 } 00261 #endif 00262 return *this; 00263 } 00264 00265 template <class _Source> 00266 _Path<_Source>& 00267 operator/=(_Source const& __source) 00268 { return _M_append(path(__source)); } 00269 00270 template<typename _Source> 00271 _Path<_Source>& 00272 append(_Source const& __source) 00273 { return _M_append(path(__source)); } 00274 00275 template<typename _InputIterator> 00276 _Path<_InputIterator, _InputIterator>& 00277 append(_InputIterator __first, _InputIterator __last) 00278 { return _M_append(path(__first, __last)); } 00279 00280 // concatenation 00281 00282 path& operator+=(const path& __x); 00283 path& operator+=(const string_type& __x); 00284 path& operator+=(const value_type* __x); 00285 path& operator+=(value_type __x); 00286 path& operator+=(basic_string_view<value_type> __x); 00287 00288 template<typename _Source> 00289 _Path<_Source>& 00290 operator+=(_Source const& __x) { return concat(__x); } 00291 00292 template<typename _CharT> 00293 _Path<_CharT*, _CharT*>& 00294 operator+=(_CharT __x); 00295 00296 template<typename _Source> 00297 _Path<_Source>& 00298 concat(_Source const& __x) 00299 { return *this += _S_convert(_S_range_begin(__x), _S_range_end(__x)); } 00300 00301 template<typename _InputIterator> 00302 _Path<_InputIterator, _InputIterator>& 00303 concat(_InputIterator __first, _InputIterator __last) 00304 { return *this += _S_convert(__first, __last); } 00305 00306 // modifiers 00307 00308 void clear() noexcept { _M_pathname.clear(); _M_split_cmpts(); } 00309 00310 path& make_preferred(); 00311 path& remove_filename(); 00312 path& replace_filename(const path& __replacement); 00313 path& replace_extension(const path& __replacement = path()); 00314 00315 void swap(path& __rhs) noexcept; 00316 00317 // native format observers 00318 00319 const string_type& native() const noexcept { return _M_pathname; } 00320 const value_type* c_str() const noexcept { return _M_pathname.c_str(); } 00321 operator string_type() const { return _M_pathname; } 00322 00323 template<typename _CharT, typename _Traits = std::char_traits<_CharT>, 00324 typename _Allocator = std::allocator<_CharT>> 00325 std::basic_string<_CharT, _Traits, _Allocator> 00326 string(const _Allocator& __a = _Allocator()) const; 00327 00328 std::string string() const; 00329 #if _GLIBCXX_USE_WCHAR_T 00330 std::wstring wstring() const; 00331 #endif 00332 std::string u8string() const; 00333 std::u16string u16string() const; 00334 std::u32string u32string() const; 00335 00336 // generic format observers 00337 template<typename _CharT, typename _Traits = std::char_traits<_CharT>, 00338 typename _Allocator = std::allocator<_CharT>> 00339 std::basic_string<_CharT, _Traits, _Allocator> 00340 generic_string(const _Allocator& __a = _Allocator()) const; 00341 00342 std::string generic_string() const; 00343 #if _GLIBCXX_USE_WCHAR_T 00344 std::wstring generic_wstring() const; 00345 #endif 00346 std::string generic_u8string() const; 00347 std::u16string generic_u16string() const; 00348 std::u32string generic_u32string() const; 00349 00350 // compare 00351 00352 int compare(const path& __p) const noexcept; 00353 int compare(const string_type& __s) const; 00354 int compare(const value_type* __s) const; 00355 int compare(const basic_string_view<value_type> __s) const; 00356 00357 // decomposition 00358 00359 path root_name() const; 00360 path root_directory() const; 00361 path root_path() const; 00362 path relative_path() const; 00363 path parent_path() const; 00364 path filename() const; 00365 path stem() const; 00366 path extension() const; 00367 00368 // query 00369 00370 [[nodiscard]] bool empty() const noexcept { return _M_pathname.empty(); } 00371 bool has_root_name() const; 00372 bool has_root_directory() const; 00373 bool has_root_path() const; 00374 bool has_relative_path() const; 00375 bool has_parent_path() const; 00376 bool has_filename() const; 00377 bool has_stem() const; 00378 bool has_extension() const; 00379 bool is_absolute() const { return has_root_directory(); } 00380 bool is_relative() const { return !is_absolute(); } 00381 00382 // generation 00383 path lexically_normal() const; 00384 path lexically_relative(const path& base) const; 00385 path lexically_proximate(const path& base) const; 00386 00387 // iterators 00388 class iterator; 00389 typedef iterator const_iterator; 00390 00391 iterator begin() const; 00392 iterator end() const; 00393 00394 private: 00395 enum class _Type : unsigned char { 00396 _Multi, _Root_name, _Root_dir, _Filename 00397 }; 00398 00399 path(string_type __str, _Type __type) : _M_pathname(__str), _M_type(__type) 00400 { 00401 __glibcxx_assert(_M_type != _Type::_Multi); 00402 } 00403 00404 enum class _Split { _Stem, _Extension }; 00405 00406 path& 00407 _M_append(path __p) 00408 { 00409 if (__p.is_absolute()) 00410 operator=(std::move(__p)); 00411 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00412 else if (__p.has_root_name() && __p.root_name() != root_name()) 00413 operator=(std::move(__p)); 00414 #endif 00415 else 00416 operator/=(const_cast<const path&>(__p)); 00417 return *this; 00418 } 00419 00420 pair<const string_type*, size_t> _M_find_extension() const; 00421 00422 template<typename _CharT> 00423 struct _Cvt; 00424 00425 static string_type 00426 _S_convert(value_type* __src, __null_terminated) 00427 { return string_type(__src); } 00428 00429 static string_type 00430 _S_convert(const value_type* __src, __null_terminated) 00431 { return string_type(__src); } 00432 00433 template<typename _Iter> 00434 static string_type 00435 _S_convert(_Iter __first, _Iter __last) 00436 { 00437 using __value_type = typename std::iterator_traits<_Iter>::value_type; 00438 return _Cvt<typename remove_cv<__value_type>::type>:: 00439 _S_convert(__first, __last); 00440 } 00441 00442 template<typename _InputIterator> 00443 static string_type 00444 _S_convert(_InputIterator __src, __null_terminated) 00445 { 00446 using _Tp = typename std::iterator_traits<_InputIterator>::value_type; 00447 std::basic_string<typename remove_cv<_Tp>::type> __tmp; 00448 for (; *__src != _Tp{}; ++__src) 00449 __tmp.push_back(*__src); 00450 return _S_convert(__tmp.c_str(), __tmp.c_str() + __tmp.size()); 00451 } 00452 00453 static string_type 00454 _S_convert_loc(const char* __first, const char* __last, 00455 const std::locale& __loc); 00456 00457 template<typename _Iter> 00458 static string_type 00459 _S_convert_loc(_Iter __first, _Iter __last, const std::locale& __loc) 00460 { 00461 const std::string __str(__first, __last); 00462 return _S_convert_loc(__str.data(), __str.data()+__str.size(), __loc); 00463 } 00464 00465 template<typename _InputIterator> 00466 static string_type 00467 _S_convert_loc(_InputIterator __src, __null_terminated, 00468 const std::locale& __loc) 00469 { 00470 std::string __tmp; 00471 while (*__src != '\0') 00472 __tmp.push_back(*__src++); 00473 return _S_convert_loc(__tmp.data(), __tmp.data()+__tmp.size(), __loc); 00474 } 00475 00476 template<typename _CharT, typename _Traits, typename _Allocator> 00477 static basic_string<_CharT, _Traits, _Allocator> 00478 _S_str_convert(const string_type&, const _Allocator& __a); 00479 00480 bool _S_is_dir_sep(value_type __ch) 00481 { 00482 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00483 return __ch == L'/' || __ch == preferred_separator; 00484 #else 00485 return __ch == '/'; 00486 #endif 00487 } 00488 00489 void _M_split_cmpts(); 00490 void _M_trim(); 00491 void _M_add_root_name(size_t __n); 00492 void _M_add_root_dir(size_t __pos); 00493 void _M_add_filename(size_t __pos, size_t __n); 00494 00495 string_type _M_pathname; 00496 00497 struct _Cmpt; 00498 using _List = _GLIBCXX_STD_C::vector<_Cmpt>; 00499 _List _M_cmpts; // empty unless _M_type == _Type::_Multi 00500 _Type _M_type = _Type::_Multi; 00501 }; 00502 00503 template<> 00504 struct path::__is_encoded_char<char> : std::true_type 00505 { using value_type = char; }; 00506 00507 template<> 00508 struct path::__is_encoded_char<wchar_t> : std::true_type 00509 { using value_type = wchar_t; }; 00510 00511 template<> 00512 struct path::__is_encoded_char<char16_t> : std::true_type 00513 { using value_type = char16_t; }; 00514 00515 template<> 00516 struct path::__is_encoded_char<char32_t> : std::true_type 00517 { using value_type = char32_t; }; 00518 00519 template<typename _Tp> 00520 struct path::__is_encoded_char<const _Tp> : __is_encoded_char<_Tp> { }; 00521 00522 inline void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); } 00523 00524 size_t hash_value(const path& __p) noexcept; 00525 00526 /// Compare paths 00527 inline bool operator<(const path& __lhs, const path& __rhs) noexcept 00528 { return __lhs.compare(__rhs) < 0; } 00529 00530 /// Compare paths 00531 inline bool operator<=(const path& __lhs, const path& __rhs) noexcept 00532 { return !(__rhs < __lhs); } 00533 00534 /// Compare paths 00535 inline bool operator>(const path& __lhs, const path& __rhs) noexcept 00536 { return __rhs < __lhs; } 00537 00538 /// Compare paths 00539 inline bool operator>=(const path& __lhs, const path& __rhs) noexcept 00540 { return !(__lhs < __rhs); } 00541 00542 /// Compare paths 00543 inline bool operator==(const path& __lhs, const path& __rhs) noexcept 00544 { return __lhs.compare(__rhs) == 0; } 00545 00546 /// Compare paths 00547 inline bool operator!=(const path& __lhs, const path& __rhs) noexcept 00548 { return !(__lhs == __rhs); } 00549 00550 /// Append one path to another 00551 inline path operator/(const path& __lhs, const path& __rhs) 00552 { 00553 path __result(__lhs); 00554 __result /= __rhs; 00555 return __result; 00556 } 00557 00558 /// Write a path to a stream 00559 template<typename _CharT, typename _Traits> 00560 basic_ostream<_CharT, _Traits>& 00561 operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p) 00562 { 00563 auto __tmp = __p.string<_CharT, _Traits>(); 00564 using __quoted_string 00565 = std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>; 00566 __os << __quoted_string{__tmp, '"', '\\'}; 00567 return __os; 00568 } 00569 00570 /// Read a path from a stream 00571 template<typename _CharT, typename _Traits> 00572 basic_istream<_CharT, _Traits>& 00573 operator>>(basic_istream<_CharT, _Traits>& __is, path& __p) 00574 { 00575 basic_string<_CharT, _Traits> __tmp; 00576 using __quoted_string 00577 = std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>; 00578 if (__is >> __quoted_string{ __tmp, '"', '\\' }) 00579 __p = std::move(__tmp); 00580 return __is; 00581 } 00582 00583 template<typename _Source> 00584 inline auto 00585 u8path(const _Source& __source) 00586 -> decltype(filesystem::path(__source, std::locale::classic())) 00587 { 00588 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00589 const std::string __u8str{__source}; 00590 return std::filesystem::u8path(__u8str.begin(), __u8str.end()); 00591 #else 00592 return path{ __source }; 00593 #endif 00594 } 00595 00596 template<typename _InputIterator> 00597 inline auto 00598 u8path(_InputIterator __first, _InputIterator __last) 00599 -> decltype(filesystem::path(__first, __last, std::locale::classic())) 00600 { 00601 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00602 codecvt_utf8<value_type> __cvt; 00603 string_type __tmp; 00604 if (__str_codecvt_in(__first, __last, __tmp, __cvt)) 00605 return path{ __tmp }; 00606 else 00607 return {}; 00608 #else 00609 return path{ __first, __last }; 00610 #endif 00611 } 00612 00613 class filesystem_error : public std::system_error 00614 { 00615 public: 00616 filesystem_error(const string& __what_arg, error_code __ec) 00617 : system_error(__ec, __what_arg) { } 00618 00619 filesystem_error(const string& __what_arg, const path& __p1, 00620 error_code __ec) 00621 : system_error(__ec, __what_arg), _M_path1(__p1) { } 00622 00623 filesystem_error(const string& __what_arg, const path& __p1, 00624 const path& __p2, error_code __ec) 00625 : system_error(__ec, __what_arg), _M_path1(__p1), _M_path2(__p2) 00626 { } 00627 00628 ~filesystem_error(); 00629 00630 const path& path1() const noexcept { return _M_path1; } 00631 const path& path2() const noexcept { return _M_path2; } 00632 const char* what() const noexcept { return _M_what.c_str(); } 00633 00634 private: 00635 std::string _M_gen_what(); 00636 00637 path _M_path1; 00638 path _M_path2; 00639 std::string _M_what = _M_gen_what(); 00640 }; 00641 00642 struct path::_Cmpt : path 00643 { 00644 _Cmpt(string_type __s, _Type __t, size_t __pos) 00645 : path(std::move(__s), __t), _M_pos(__pos) { } 00646 00647 _Cmpt() : _M_pos(-1) { } 00648 00649 size_t _M_pos; 00650 }; 00651 00652 // specialize _Cvt for degenerate 'noconv' case 00653 template<> 00654 struct path::_Cvt<path::value_type> 00655 { 00656 template<typename _Iter> 00657 static string_type 00658 _S_convert(_Iter __first, _Iter __last) 00659 { return string_type{__first, __last}; } 00660 }; 00661 00662 template<typename _CharT> 00663 struct path::_Cvt 00664 { 00665 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00666 static string_type 00667 _S_wconvert(const char* __f, const char* __l, true_type) 00668 { 00669 using _Cvt = std::codecvt<wchar_t, char, mbstate_t>; 00670 const auto& __cvt = std::use_facet<_Cvt>(std::locale{}); 00671 std::wstring __wstr; 00672 if (__str_codecvt_in(__f, __l, __wstr, __cvt)) 00673 return __wstr; 00674 _GLIBCXX_THROW_OR_ABORT(filesystem_error( 00675 "Cannot convert character sequence", 00676 std::make_error_code(errc::illegal_byte_sequence))); 00677 } 00678 00679 static string_type 00680 _S_wconvert(const _CharT* __f, const _CharT* __l, false_type) 00681 { 00682 std::codecvt_utf8<_CharT> __cvt; 00683 std::string __str; 00684 if (__str_codecvt_out(__f, __l, __str, __cvt)) 00685 { 00686 const char* __f2 = __str.data(); 00687 const char* __l2 = __f2 + __str.size(); 00688 std::codecvt_utf8<wchar_t> __wcvt; 00689 std::wstring __wstr; 00690 if (__str_codecvt_in(__f2, __l2, __wstr, __wcvt)) 00691 return __wstr; 00692 } 00693 _GLIBCXX_THROW_OR_ABORT(filesystem_error( 00694 "Cannot convert character sequence", 00695 std::make_error_code(errc::illegal_byte_sequence))); 00696 } 00697 00698 static string_type 00699 _S_convert(const _CharT* __f, const _CharT* __l) 00700 { 00701 return _S_wconvert(__f, __l, is_same<_CharT, char>{}); 00702 } 00703 #else 00704 static string_type 00705 _S_convert(const _CharT* __f, const _CharT* __l) 00706 { 00707 std::codecvt_utf8<_CharT> __cvt; 00708 std::string __str; 00709 if (__str_codecvt_out(__f, __l, __str, __cvt)) 00710 return __str; 00711 _GLIBCXX_THROW_OR_ABORT(filesystem_error( 00712 "Cannot convert character sequence", 00713 std::make_error_code(errc::illegal_byte_sequence))); 00714 } 00715 #endif 00716 00717 static string_type 00718 _S_convert(_CharT* __f, _CharT* __l) 00719 { 00720 return _S_convert(const_cast<const _CharT*>(__f), 00721 const_cast<const _CharT*>(__l)); 00722 } 00723 00724 template<typename _Iter> 00725 static string_type 00726 _S_convert(_Iter __first, _Iter __last) 00727 { 00728 const std::basic_string<_CharT> __str(__first, __last); 00729 return _S_convert(__str.data(), __str.data() + __str.size()); 00730 } 00731 00732 template<typename _Iter, typename _Cont> 00733 static string_type 00734 _S_convert(__gnu_cxx::__normal_iterator<_Iter, _Cont> __first, 00735 __gnu_cxx::__normal_iterator<_Iter, _Cont> __last) 00736 { return _S_convert(__first.base(), __last.base()); } 00737 }; 00738 00739 /// An iterator for the components of a path 00740 class path::iterator 00741 { 00742 public: 00743 using difference_type = std::ptrdiff_t; 00744 using value_type = path; 00745 using reference = const path&; 00746 using pointer = const path*; 00747 using iterator_category = std::bidirectional_iterator_tag; 00748 00749 iterator() : _M_path(nullptr), _M_cur(), _M_at_end() { } 00750 00751 iterator(const iterator&) = default; 00752 iterator& operator=(const iterator&) = default; 00753 00754 reference operator*() const; 00755 pointer operator->() const { return std::__addressof(**this); } 00756 00757 iterator& operator++(); 00758 iterator operator++(int) { auto __tmp = *this; ++*this; return __tmp; } 00759 00760 iterator& operator--(); 00761 iterator operator--(int) { auto __tmp = *this; --*this; return __tmp; } 00762 00763 friend bool operator==(const iterator& __lhs, const iterator& __rhs) 00764 { return __lhs._M_equals(__rhs); } 00765 00766 friend bool operator!=(const iterator& __lhs, const iterator& __rhs) 00767 { return !__lhs._M_equals(__rhs); } 00768 00769 private: 00770 friend class path; 00771 00772 iterator(const path* __path, path::_List::const_iterator __iter) 00773 : _M_path(__path), _M_cur(__iter), _M_at_end() 00774 { } 00775 00776 iterator(const path* __path, bool __at_end) 00777 : _M_path(__path), _M_cur(), _M_at_end(__at_end) 00778 { } 00779 00780 bool _M_equals(iterator) const; 00781 00782 const path* _M_path; 00783 path::_List::const_iterator _M_cur; 00784 bool _M_at_end; // only used when type != _Multi 00785 }; 00786 00787 00788 inline path& 00789 path::operator=(path&& __p) noexcept 00790 { 00791 _M_pathname = std::move(__p._M_pathname); 00792 _M_cmpts = std::move(__p._M_cmpts); 00793 _M_type = __p._M_type; 00794 __p.clear(); 00795 return *this; 00796 } 00797 00798 inline path& 00799 path::operator=(string_type&& __source) 00800 { return *this = path(std::move(__source)); } 00801 00802 inline path& 00803 path::assign(string_type&& __source) 00804 { return *this = path(std::move(__source)); } 00805 00806 inline path& 00807 path::operator+=(const path& __p) 00808 { 00809 return operator+=(__p.native()); 00810 } 00811 00812 inline path& 00813 path::operator+=(const string_type& __x) 00814 { 00815 _M_pathname += __x; 00816 _M_split_cmpts(); 00817 return *this; 00818 } 00819 00820 inline path& 00821 path::operator+=(const value_type* __x) 00822 { 00823 _M_pathname += __x; 00824 _M_split_cmpts(); 00825 return *this; 00826 } 00827 00828 inline path& 00829 path::operator+=(value_type __x) 00830 { 00831 _M_pathname += __x; 00832 _M_split_cmpts(); 00833 return *this; 00834 } 00835 00836 inline path& 00837 path::operator+=(basic_string_view<value_type> __x) 00838 { 00839 _M_pathname.append(__x.data(), __x.size()); 00840 _M_split_cmpts(); 00841 return *this; 00842 } 00843 00844 template<typename _CharT> 00845 inline path::_Path<_CharT*, _CharT*>& 00846 path::operator+=(_CharT __x) 00847 { 00848 auto* __addr = std::__addressof(__x); 00849 return concat(__addr, __addr + 1); 00850 } 00851 00852 inline path& 00853 path::make_preferred() 00854 { 00855 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00856 std::replace(_M_pathname.begin(), _M_pathname.end(), L'/', 00857 preferred_separator); 00858 #endif 00859 return *this; 00860 } 00861 00862 inline void path::swap(path& __rhs) noexcept 00863 { 00864 _M_pathname.swap(__rhs._M_pathname); 00865 _M_cmpts.swap(__rhs._M_cmpts); 00866 std::swap(_M_type, __rhs._M_type); 00867 } 00868 00869 template<typename _CharT, typename _Traits, typename _Allocator> 00870 std::basic_string<_CharT, _Traits, _Allocator> 00871 path::_S_str_convert(const string_type& __str, const _Allocator& __a) 00872 { 00873 if (__str.size() == 0) 00874 return std::basic_string<_CharT, _Traits, _Allocator>(__a); 00875 00876 const value_type* __first = __str.data(); 00877 const value_type* __last = __first + __str.size(); 00878 00879 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00880 using _CharAlloc = __alloc_rebind<_Allocator, char>; 00881 using _String = basic_string<char, char_traits<char>, _CharAlloc>; 00882 using _WString = basic_string<_CharT, _Traits, _Allocator>; 00883 00884 // use codecvt_utf8<wchar_t> to convert native string to UTF-8 00885 codecvt_utf8<value_type> __cvt; 00886 _String __u8str{_CharAlloc{__a}}; 00887 if (__str_codecvt_out(__first, __last, __u8str, __cvt)) 00888 { 00889 if constexpr (is_same_v<_CharT, char>) 00890 return __u8str; 00891 else 00892 { 00893 _WString __wstr; 00894 // use codecvt_utf8<_CharT> to convert UTF-8 to wide string 00895 codecvt_utf8<_CharT> __cvt; 00896 const char* __f = __u8str.data(); 00897 const char* __l = __f + __u8str.size(); 00898 if (__str_codecvt_in(__f, __l, __wstr, __cvt)) 00899 return __wstr; 00900 } 00901 } 00902 #else 00903 codecvt_utf8<_CharT> __cvt; 00904 basic_string<_CharT, _Traits, _Allocator> __wstr{__a}; 00905 if (__str_codecvt_in(__first, __last, __wstr, __cvt)) 00906 return __wstr; 00907 #endif 00908 _GLIBCXX_THROW_OR_ABORT(filesystem_error( 00909 "Cannot convert character sequence", 00910 std::make_error_code(errc::illegal_byte_sequence))); 00911 } 00912 00913 template<typename _CharT, typename _Traits, typename _Allocator> 00914 inline basic_string<_CharT, _Traits, _Allocator> 00915 path::string(const _Allocator& __a) const 00916 { 00917 if constexpr (is_same_v<_CharT, value_type>) 00918 #if _GLIBCXX_USE_CXX11_ABI 00919 return { _M_pathname, __a }; 00920 #else 00921 return { _M_pathname, string_type::size_type(0), __a }; 00922 #endif 00923 else 00924 return _S_str_convert<_CharT, _Traits>(_M_pathname, __a); 00925 } 00926 00927 inline std::string 00928 path::string() const { return string<char>(); } 00929 00930 #if _GLIBCXX_USE_WCHAR_T 00931 inline std::wstring 00932 path::wstring() const { return string<wchar_t>(); } 00933 #endif 00934 00935 inline std::string 00936 path::u8string() const 00937 { 00938 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00939 std::string __str; 00940 // convert from native encoding to UTF-8 00941 codecvt_utf8<value_type> __cvt; 00942 const value_type* __first = _M_pathname.data(); 00943 const value_type* __last = __first + _M_pathname.size(); 00944 if (__str_codecvt_out(__first, __last, __str, __cvt)) 00945 return __str; 00946 _GLIBCXX_THROW_OR_ABORT(filesystem_error( 00947 "Cannot convert character sequence", 00948 std::make_error_code(errc::illegal_byte_sequence))); 00949 #else 00950 return _M_pathname; 00951 #endif 00952 } 00953 00954 inline std::u16string 00955 path::u16string() const { return string<char16_t>(); } 00956 00957 inline std::u32string 00958 path::u32string() const { return string<char32_t>(); } 00959 00960 template<typename _CharT, typename _Traits, typename _Allocator> 00961 inline std::basic_string<_CharT, _Traits, _Allocator> 00962 path::generic_string(const _Allocator& __a) const 00963 { 00964 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS 00965 const value_type __slash = L'/'; 00966 #else 00967 const value_type __slash = '/'; 00968 #endif 00969 string_type __str(__a); 00970 00971 if (_M_type == _Type::_Root_dir) 00972 __str.assign(1, __slash); 00973 else 00974 { 00975 __str.reserve(_M_pathname.size()); 00976 bool __add_slash = false; 00977 for (auto& __elem : *this) 00978 { 00979 if (__add_slash) 00980 __str += __slash; 00981 __str += __elem._M_pathname; 00982 __add_slash = __elem._M_type == _Type::_Filename; 00983 } 00984 } 00985 00986 if constexpr (is_same_v<_CharT, value_type>) 00987 return __str; 00988 else 00989 return _S_str_convert<_CharT, _Traits>(__str, __a); 00990 } 00991 00992 inline std::string 00993 path::generic_string() const 00994 { return generic_string<char>(); } 00995 00996 #if _GLIBCXX_USE_WCHAR_T 00997 inline std::wstring 00998 path::generic_wstring() const 00999 { return generic_string<wchar_t>(); } 01000 #endif 01001 01002 inline std::string 01003 path::generic_u8string() const 01004 { return generic_string(); } 01005 01006 inline std::u16string 01007 path::generic_u16string() const 01008 { return generic_string<char16_t>(); } 01009 01010 inline std::u32string 01011 path::generic_u32string() const 01012 { return generic_string<char32_t>(); } 01013 01014 inline int 01015 path::compare(const string_type& __s) const { return compare(path(__s)); } 01016 01017 inline int 01018 path::compare(const value_type* __s) const { return compare(path(__s)); } 01019 01020 inline int 01021 path::compare(basic_string_view<value_type> __s) const 01022 { return compare(path(__s)); } 01023 01024 inline path 01025 path::filename() const 01026 { 01027 if (empty()) 01028 return {}; 01029 else if (_M_type == _Type::_Filename) 01030 return *this; 01031 else if (_M_type == _Type::_Multi) 01032 { 01033 if (_M_pathname.back() == preferred_separator) 01034 return {}; 01035 auto& __last = *--end(); 01036 if (__last._M_type == _Type::_Filename) 01037 return __last; 01038 } 01039 return {}; 01040 } 01041 01042 inline path 01043 path::stem() const 01044 { 01045 auto ext = _M_find_extension(); 01046 if (ext.first && ext.second != 0) 01047 return path{ext.first->substr(0, ext.second)}; 01048 return {}; 01049 } 01050 01051 inline path 01052 path::extension() const 01053 { 01054 auto ext = _M_find_extension(); 01055 if (ext.first && ext.second != string_type::npos) 01056 return path{ext.first->substr(ext.second)}; 01057 return {}; 01058 } 01059 01060 inline bool 01061 path::has_stem() const 01062 { 01063 auto ext = _M_find_extension(); 01064 return ext.first && ext.second != 0; 01065 } 01066 01067 inline bool 01068 path::has_extension() const 01069 { 01070 auto ext = _M_find_extension(); 01071 return ext.first && ext.second != string_type::npos; 01072 } 01073 01074 inline path::iterator 01075 path::begin() const 01076 { 01077 if (_M_type == _Type::_Multi) 01078 return iterator(this, _M_cmpts.begin()); 01079 return iterator(this, false); 01080 } 01081 01082 inline path::iterator 01083 path::end() const 01084 { 01085 if (_M_type == _Type::_Multi) 01086 return iterator(this, _M_cmpts.end()); 01087 return iterator(this, true); 01088 } 01089 01090 inline path::iterator& 01091 path::iterator::operator++() 01092 { 01093 __glibcxx_assert(_M_path != nullptr); 01094 if (_M_path->_M_type == _Type::_Multi) 01095 { 01096 __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end()); 01097 ++_M_cur; 01098 } 01099 else 01100 { 01101 __glibcxx_assert(!_M_at_end); 01102 _M_at_end = true; 01103 } 01104 return *this; 01105 } 01106 01107 inline path::iterator& 01108 path::iterator::operator--() 01109 { 01110 __glibcxx_assert(_M_path != nullptr); 01111 if (_M_path->_M_type == _Type::_Multi) 01112 { 01113 __glibcxx_assert(_M_cur != _M_path->_M_cmpts.begin()); 01114 --_M_cur; 01115 } 01116 else 01117 { 01118 __glibcxx_assert(_M_at_end); 01119 _M_at_end = false; 01120 } 01121 return *this; 01122 } 01123 01124 inline path::iterator::reference 01125 path::iterator::operator*() const 01126 { 01127 __glibcxx_assert(_M_path != nullptr); 01128 if (_M_path->_M_type == _Type::_Multi) 01129 { 01130 __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end()); 01131 return *_M_cur; 01132 } 01133 return *_M_path; 01134 } 01135 01136 inline bool 01137 path::iterator::_M_equals(iterator __rhs) const 01138 { 01139 if (_M_path != __rhs._M_path) 01140 return false; 01141 if (_M_path == nullptr) 01142 return true; 01143 if (_M_path->_M_type == path::_Type::_Multi) 01144 return _M_cur == __rhs._M_cur; 01145 return _M_at_end == __rhs._M_at_end; 01146 } 01147 01148 // @} group filesystem 01149 _GLIBCXX_END_NAMESPACE_CXX11 01150 } // namespace filesystem 01151 01152 _GLIBCXX_END_NAMESPACE_VERSION 01153 } // namespace std 01154 01155 #endif // C++17 01156 01157 #endif // _GLIBCXX_FS_PATH_H