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