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