| 1 | // filesystem path.hpp ---------------------------------------------------------------// |
| 2 | |
| 3 | // Copyright Beman Dawes 2002-2005, 2009 |
| 4 | // Copyright Vladimir Prus 2002 |
| 5 | |
| 6 | // Distributed under the Boost Software License, Version 1.0. |
| 7 | // See http://www.boost.org/LICENSE_1_0.txt |
| 8 | |
| 9 | // Library home page: http://www.boost.org/libs/filesystem |
| 10 | |
| 11 | // path::stem(), extension(), and replace_extension() are based on |
| 12 | // basename(), extension(), and change_extension() from the original |
| 13 | // filesystem/convenience.hpp header by Vladimir Prus. |
| 14 | |
| 15 | #ifndef BOOST_FILESYSTEM_PATH_HPP |
| 16 | #define BOOST_FILESYSTEM_PATH_HPP |
| 17 | |
| 18 | #include <boost/config.hpp> |
| 19 | |
| 20 | # if defined( BOOST_NO_STD_WSTRING ) |
| 21 | # error Configuration not supported: Boost.Filesystem V3 and later requires std::wstring support |
| 22 | # endif |
| 23 | |
| 24 | #include <boost/filesystem/config.hpp> |
| 25 | #include <boost/filesystem/path_traits.hpp> // includes <cwchar> |
| 26 | #include <boost/system/error_code.hpp> |
| 27 | #include <boost/system/system_error.hpp> |
| 28 | #include <boost/iterator/iterator_facade.hpp> |
| 29 | #include <boost/shared_ptr.hpp> |
| 30 | #include <boost/io/detail/quoted_manip.hpp> |
| 31 | #include <boost/static_assert.hpp> |
| 32 | #include <boost/functional/hash_fwd.hpp> |
| 33 | #include <boost/type_traits/is_integral.hpp> |
| 34 | #include <string> |
| 35 | #include <iterator> |
| 36 | #include <cstring> |
| 37 | #include <iosfwd> |
| 38 | #include <stdexcept> |
| 39 | #include <cassert> |
| 40 | #include <locale> |
| 41 | #include <algorithm> |
| 42 | |
| 43 | #include <boost/config/abi_prefix.hpp> // must be the last #include |
| 44 | |
| 45 | namespace boost |
| 46 | { |
| 47 | namespace filesystem |
| 48 | { |
| 49 | |
| 50 | //------------------------------------------------------------------------------------// |
| 51 | // // |
| 52 | // class path // |
| 53 | // // |
| 54 | //------------------------------------------------------------------------------------// |
| 55 | |
| 56 | class BOOST_FILESYSTEM_DECL path |
| 57 | { |
| 58 | public: |
| 59 | |
| 60 | // value_type is the character type used by the operating system API to |
| 61 | // represent paths. |
| 62 | |
| 63 | # ifdef BOOST_WINDOWS_API |
| 64 | typedef wchar_t value_type; |
| 65 | BOOST_STATIC_CONSTEXPR value_type separator = L'/'; |
| 66 | BOOST_STATIC_CONSTEXPR value_type preferred_separator = L'\\'; |
| 67 | BOOST_STATIC_CONSTEXPR value_type dot = L'.'; |
| 68 | # else |
| 69 | typedef char value_type; |
| 70 | BOOST_STATIC_CONSTEXPR value_type separator = '/'; |
| 71 | BOOST_STATIC_CONSTEXPR value_type preferred_separator = '/'; |
| 72 | BOOST_STATIC_CONSTEXPR value_type dot = '.'; |
| 73 | # endif |
| 74 | typedef std::basic_string<value_type> string_type; |
| 75 | typedef std::codecvt<wchar_t, char, |
| 76 | std::mbstate_t> codecvt_type; |
| 77 | |
| 78 | |
| 79 | // ----- character encoding conversions ----- |
| 80 | |
| 81 | // Following the principle of least astonishment, path input arguments |
| 82 | // passed to or obtained from the operating system via objects of |
| 83 | // class path behave as if they were directly passed to or |
| 84 | // obtained from the O/S API, unless conversion is explicitly requested. |
| 85 | // |
| 86 | // POSIX specfies that path strings are passed unchanged to and from the |
| 87 | // API. Note that this is different from the POSIX command line utilities, |
| 88 | // which convert according to a locale. |
| 89 | // |
| 90 | // Thus for POSIX, char strings do not undergo conversion. wchar_t strings |
| 91 | // are converted to/from char using the path locale or, if a conversion |
| 92 | // argument is given, using a conversion object modeled on |
| 93 | // std::wstring_convert. |
| 94 | // |
| 95 | // The path locale, which is global to the thread, can be changed by the |
| 96 | // imbue() function. It is initialized to an implementation defined locale. |
| 97 | // |
| 98 | // For Windows, wchar_t strings do not undergo conversion. char strings |
| 99 | // are converted using the "ANSI" or "OEM" code pages, as determined by |
| 100 | // the AreFileApisANSI() function, or, if a conversion argument is given, |
| 101 | // using a conversion object modeled on std::wstring_convert. |
| 102 | // |
| 103 | // See m_pathname comments for further important rationale. |
| 104 | |
| 105 | // TODO: rules needed for operating systems that use / or . |
| 106 | // differently, or format directory paths differently from file paths. |
| 107 | // |
| 108 | // ********************************************************************************** |
| 109 | // |
| 110 | // More work needed: How to handle an operating system that may have |
| 111 | // slash characters or dot characters in valid filenames, either because |
| 112 | // it doesn't follow the POSIX standard, or because it allows MBCS |
| 113 | // filename encodings that may contain slash or dot characters. For |
| 114 | // example, ISO/IEC 2022 (JIS) encoding which allows switching to |
| 115 | // JIS x0208-1983 encoding. A valid filename in this set of encodings is |
| 116 | // 0x1B 0x24 0x42 [switch to X0208-1983] 0x24 0x2F [U+304F Kiragana letter KU] |
| 117 | // ^^^^ |
| 118 | // Note that 0x2F is the ASCII slash character |
| 119 | // |
| 120 | // ********************************************************************************** |
| 121 | |
| 122 | // Supported source arguments: half-open iterator range, container, c-array, |
| 123 | // and single pointer to null terminated string. |
| 124 | |
| 125 | // All source arguments except pointers to null terminated byte strings support |
| 126 | // multi-byte character strings which may have embedded nulls. Embedded null |
| 127 | // support is required for some Asian languages on Windows. |
| 128 | |
| 129 | // "const codecvt_type& cvt=codecvt()" default arguments are not used because this |
| 130 | // limits the impact of locale("") initialization failures on POSIX systems to programs |
| 131 | // that actually depend on locale(""). It further ensures that exceptions thrown |
| 132 | // as a result of such failues occur after main() has started, so can be caught. |
| 133 | |
| 134 | // ----- constructors ----- |
| 135 | |
| 136 | path() BOOST_NOEXCEPT {} |
| 137 | path(const path& p) : m_pathname(p.m_pathname) {} |
| 138 | |
| 139 | template <class Source> |
| 140 | path(Source const& source, |
| 141 | typename boost::enable_if<path_traits::is_pathable< |
| 142 | typename boost::decay<Source>::type> >::type* =0) |
| 143 | { |
| 144 | path_traits::dispatch(source, m_pathname); |
| 145 | } |
| 146 | |
| 147 | path(const value_type* s) : m_pathname(s) {} |
| 148 | path(value_type* s) : m_pathname(s) {} |
| 149 | path(const string_type& s) : m_pathname(s) {} |
| 150 | path(string_type& s) : m_pathname(s) {} |
| 151 | |
| 152 | // As of October 2015 the interaction between noexcept and =default is so troublesome |
| 153 | // for VC++, GCC, and probably other compilers, that =default is not used with noexcept |
| 154 | // functions. GCC is not even consistent for the same release on different platforms. |
| 155 | |
| 156 | # if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) |
| 157 | path(path&& p) BOOST_NOEXCEPT { m_pathname = std::move(p.m_pathname); } |
| 158 | path& operator=(path&& p) BOOST_NOEXCEPT |
| 159 | { m_pathname = std::move(p.m_pathname); return *this; } |
| 160 | # endif |
| 161 | |
| 162 | template <class Source> |
| 163 | path(Source const& source, const codecvt_type& cvt) |
| 164 | { |
| 165 | path_traits::dispatch(source, m_pathname, cvt); |
| 166 | } |
| 167 | |
| 168 | template <class InputIterator> |
| 169 | path(InputIterator begin, InputIterator end) |
| 170 | { |
| 171 | if (begin != end) |
| 172 | { |
| 173 | // convert requires contiguous string, so copy |
| 174 | std::basic_string<typename std::iterator_traits<InputIterator>::value_type> |
| 175 | seq(begin, end); |
| 176 | path_traits::convert(seq.c_str(), seq.c_str()+seq.size(), m_pathname); |
| 177 | } |
| 178 | } |
| 179 | |
| 180 | template <class InputIterator> |
| 181 | path(InputIterator begin, InputIterator end, const codecvt_type& cvt) |
| 182 | { |
| 183 | if (begin != end) |
| 184 | { |
| 185 | // convert requires contiguous string, so copy |
| 186 | std::basic_string<typename std::iterator_traits<InputIterator>::value_type> |
| 187 | seq(begin, end); |
| 188 | path_traits::convert(seq.c_str(), seq.c_str()+seq.size(), m_pathname, cvt); |
| 189 | } |
| 190 | } |
| 191 | |
| 192 | // ----- assignments ----- |
| 193 | |
| 194 | path& operator=(const path& p) |
| 195 | { |
| 196 | m_pathname = p.m_pathname; |
| 197 | return *this; |
| 198 | } |
| 199 | |
| 200 | template <class Source> |
| 201 | typename boost::enable_if<path_traits::is_pathable< |
| 202 | typename boost::decay<Source>::type>, path&>::type |
| 203 | operator=(Source const& source) |
| 204 | { |
| 205 | m_pathname.clear(); |
| 206 | path_traits::dispatch(source, m_pathname); |
| 207 | return *this; |
| 208 | } |
| 209 | |
| 210 | // value_type overloads |
| 211 | |
| 212 | path& operator=(const value_type* ptr) // required in case ptr overlaps *this |
| 213 | {m_pathname = ptr; return *this;} |
| 214 | path& operator=(value_type* ptr) // required in case ptr overlaps *this |
| 215 | {m_pathname = ptr; return *this;} |
| 216 | path& operator=(const string_type& s) {m_pathname = s; return *this;} |
| 217 | path& operator=(string_type& s) {m_pathname = s; return *this;} |
| 218 | |
| 219 | path& assign(const value_type* ptr, const codecvt_type&) // required in case ptr overlaps *this |
| 220 | {m_pathname = ptr; return *this;} |
| 221 | template <class Source> |
| 222 | path& assign(Source const& source, const codecvt_type& cvt) |
| 223 | { |
| 224 | m_pathname.clear(); |
| 225 | path_traits::dispatch(source, m_pathname, cvt); |
| 226 | return *this; |
| 227 | } |
| 228 | |
| 229 | template <class InputIterator> |
| 230 | path& assign(InputIterator begin, InputIterator end) |
| 231 | { |
| 232 | m_pathname.clear(); |
| 233 | if (begin != end) |
| 234 | { |
| 235 | std::basic_string<typename std::iterator_traits<InputIterator>::value_type> |
| 236 | seq(begin, end); |
| 237 | path_traits::convert(seq.c_str(), seq.c_str()+seq.size(), m_pathname); |
| 238 | } |
| 239 | return *this; |
| 240 | } |
| 241 | |
| 242 | template <class InputIterator> |
| 243 | path& assign(InputIterator begin, InputIterator end, const codecvt_type& cvt) |
| 244 | { |
| 245 | m_pathname.clear(); |
| 246 | if (begin != end) |
| 247 | { |
| 248 | std::basic_string<typename std::iterator_traits<InputIterator>::value_type> |
| 249 | seq(begin, end); |
| 250 | path_traits::convert(seq.c_str(), seq.c_str()+seq.size(), m_pathname, cvt); |
| 251 | } |
| 252 | return *this; |
| 253 | } |
| 254 | |
| 255 | // ----- concatenation ----- |
| 256 | |
| 257 | template <class Source> |
| 258 | typename boost::enable_if<path_traits::is_pathable< |
| 259 | typename boost::decay<Source>::type>, path&>::type |
| 260 | operator+=(Source const& source) |
| 261 | { |
| 262 | return concat(source); |
| 263 | } |
| 264 | |
| 265 | // value_type overloads. Same rationale as for constructors above |
| 266 | path& operator+=(const path& p) { m_pathname += p.m_pathname; return *this; } |
| 267 | path& operator+=(const value_type* ptr) { m_pathname += ptr; return *this; } |
| 268 | path& operator+=(value_type* ptr) { m_pathname += ptr; return *this; } |
| 269 | path& operator+=(const string_type& s) { m_pathname += s; return *this; } |
| 270 | path& operator+=(string_type& s) { m_pathname += s; return *this; } |
| 271 | path& operator+=(value_type c) { m_pathname += c; return *this; } |
| 272 | |
| 273 | template <class CharT> |
| 274 | typename boost::enable_if<is_integral<CharT>, path&>::type |
| 275 | operator+=(CharT c) |
| 276 | { |
| 277 | CharT tmp[2]; |
| 278 | tmp[0] = c; |
| 279 | tmp[1] = 0; |
| 280 | return concat(tmp); |
| 281 | } |
| 282 | |
| 283 | template <class Source> |
| 284 | path& concat(Source const& source) |
| 285 | { |
| 286 | path_traits::dispatch(source, m_pathname); |
| 287 | return *this; |
| 288 | } |
| 289 | |
| 290 | template <class Source> |
| 291 | path& concat(Source const& source, const codecvt_type& cvt) |
| 292 | { |
| 293 | path_traits::dispatch(source, m_pathname, cvt); |
| 294 | return *this; |
| 295 | } |
| 296 | |
| 297 | template <class InputIterator> |
| 298 | path& concat(InputIterator begin, InputIterator end) |
| 299 | { |
| 300 | if (begin == end) |
| 301 | return *this; |
| 302 | std::basic_string<typename std::iterator_traits<InputIterator>::value_type> |
| 303 | seq(begin, end); |
| 304 | path_traits::convert(seq.c_str(), seq.c_str()+seq.size(), m_pathname); |
| 305 | return *this; |
| 306 | } |
| 307 | |
| 308 | template <class InputIterator> |
| 309 | path& concat(InputIterator begin, InputIterator end, const codecvt_type& cvt) |
| 310 | { |
| 311 | if (begin == end) |
| 312 | return *this; |
| 313 | std::basic_string<typename std::iterator_traits<InputIterator>::value_type> |
| 314 | seq(begin, end); |
| 315 | path_traits::convert(seq.c_str(), seq.c_str()+seq.size(), m_pathname, cvt); |
| 316 | return *this; |
| 317 | } |
| 318 | |
| 319 | // ----- appends ----- |
| 320 | |
| 321 | // if a separator is added, it is the preferred separator for the platform; |
| 322 | // slash for POSIX, backslash for Windows |
| 323 | |
| 324 | path& operator/=(const path& p); |
| 325 | |
| 326 | template <class Source> |
| 327 | typename boost::enable_if<path_traits::is_pathable< |
| 328 | typename boost::decay<Source>::type>, path&>::type |
| 329 | operator/=(Source const& source) |
| 330 | { |
| 331 | return append(source); |
| 332 | } |
| 333 | |
| 334 | path& operator/=(const value_type* ptr); |
| 335 | path& operator/=(value_type* ptr) |
| 336 | { |
| 337 | return this->operator/=(const_cast<const value_type*>(ptr)); |
| 338 | } |
| 339 | path& operator/=(const string_type& s) { return this->operator/=(path(s)); } |
| 340 | path& operator/=(string_type& s) { return this->operator/=(path(s)); } |
| 341 | |
| 342 | path& append(const value_type* ptr) // required in case ptr overlaps *this |
| 343 | { |
| 344 | this->operator/=(ptr); |
| 345 | return *this; |
| 346 | } |
| 347 | |
| 348 | path& append(const value_type* ptr, const codecvt_type&) // required in case ptr overlaps *this |
| 349 | { |
| 350 | this->operator/=(ptr); |
| 351 | return *this; |
| 352 | } |
| 353 | |
| 354 | template <class Source> |
| 355 | path& append(Source const& source); |
| 356 | |
| 357 | template <class Source> |
| 358 | path& append(Source const& source, const codecvt_type& cvt); |
| 359 | |
| 360 | template <class InputIterator> |
| 361 | path& append(InputIterator begin, InputIterator end); |
| 362 | |
| 363 | template <class InputIterator> |
| 364 | path& append(InputIterator begin, InputIterator end, const codecvt_type& cvt); |
| 365 | |
| 366 | // ----- modifiers ----- |
| 367 | |
| 368 | void clear() BOOST_NOEXCEPT { m_pathname.clear(); } |
| 369 | path& make_preferred() |
| 370 | # ifdef BOOST_POSIX_API |
| 371 | { return *this; } // POSIX no effect |
| 372 | # else // BOOST_WINDOWS_API |
| 373 | ; // change slashes to backslashes |
| 374 | # endif |
| 375 | path& remove_filename(); |
| 376 | path& remove_trailing_separator(); |
| 377 | path& replace_extension(const path& new_extension = path()); |
| 378 | void swap(path& rhs) BOOST_NOEXCEPT { m_pathname.swap(rhs.m_pathname); } |
| 379 | |
| 380 | // ----- observers ----- |
| 381 | |
| 382 | // For operating systems that format file paths differently than directory |
| 383 | // paths, return values from observers are formatted as file names unless there |
| 384 | // is a trailing separator, in which case returns are formatted as directory |
| 385 | // paths. POSIX and Windows make no such distinction. |
| 386 | |
| 387 | // Implementations are permitted to return const values or const references. |
| 388 | |
| 389 | // The string or path returned by an observer are specified as being formatted |
| 390 | // as "native" or "generic". |
| 391 | // |
| 392 | // For POSIX, these are all the same format; slashes and backslashes are as input and |
| 393 | // are not modified. |
| 394 | // |
| 395 | // For Windows, native: as input; slashes and backslashes are not modified; |
| 396 | // this is the format of the internally stored string. |
| 397 | // generic: backslashes are converted to slashes |
| 398 | |
| 399 | // ----- native format observers ----- |
| 400 | |
| 401 | const string_type& native() const BOOST_NOEXCEPT { return m_pathname; } |
| 402 | const value_type* c_str() const BOOST_NOEXCEPT { return m_pathname.c_str(); } |
| 403 | string_type::size_type size() const BOOST_NOEXCEPT { return m_pathname.size(); } |
| 404 | |
| 405 | template <class String> |
| 406 | String string() const; |
| 407 | |
| 408 | template <class String> |
| 409 | String string(const codecvt_type& cvt) const; |
| 410 | |
| 411 | # ifdef BOOST_WINDOWS_API |
| 412 | const std::string string() const |
| 413 | { |
| 414 | std::string tmp; |
| 415 | if (!m_pathname.empty()) |
| 416 | path_traits::convert(&*m_pathname.begin(), &*m_pathname.begin()+m_pathname.size(), |
| 417 | tmp); |
| 418 | return tmp; |
| 419 | } |
| 420 | const std::string string(const codecvt_type& cvt) const |
| 421 | { |
| 422 | std::string tmp; |
| 423 | if (!m_pathname.empty()) |
| 424 | path_traits::convert(&*m_pathname.begin(), &*m_pathname.begin()+m_pathname.size(), |
| 425 | tmp, cvt); |
| 426 | return tmp; |
| 427 | } |
| 428 | |
| 429 | // string_type is std::wstring, so there is no conversion |
| 430 | const std::wstring& wstring() const { return m_pathname; } |
| 431 | const std::wstring& wstring(const codecvt_type&) const { return m_pathname; } |
| 432 | |
| 433 | # else // BOOST_POSIX_API |
| 434 | // string_type is std::string, so there is no conversion |
| 435 | const std::string& string() const { return m_pathname; } |
| 436 | const std::string& string(const codecvt_type&) const { return m_pathname; } |
| 437 | |
| 438 | const std::wstring wstring() const |
| 439 | { |
| 440 | std::wstring tmp; |
| 441 | if (!m_pathname.empty()) |
| 442 | path_traits::convert(&*m_pathname.begin(), &*m_pathname.begin()+m_pathname.size(), |
| 443 | tmp); |
| 444 | return tmp; |
| 445 | } |
| 446 | const std::wstring wstring(const codecvt_type& cvt) const |
| 447 | { |
| 448 | std::wstring tmp; |
| 449 | if (!m_pathname.empty()) |
| 450 | path_traits::convert(&*m_pathname.begin(), &*m_pathname.begin()+m_pathname.size(), |
| 451 | tmp, cvt); |
| 452 | return tmp; |
| 453 | } |
| 454 | |
| 455 | # endif |
| 456 | |
| 457 | // ----- generic format observers ----- |
| 458 | |
| 459 | // Experimental generic function returning generic formatted path (i.e. separators |
| 460 | // are forward slashes). Motivation: simpler than a family of generic_*string |
| 461 | // functions. |
| 462 | path generic_path() const |
| 463 | { |
| 464 | # ifdef BOOST_WINDOWS_API |
| 465 | path tmp; |
| 466 | std::replace_copy(m_pathname.begin(), m_pathname.end(), |
| 467 | std::back_inserter(tmp.m_pathname), L'\\', L'/'); |
| 468 | return tmp; |
| 469 | # else |
| 470 | return path(*this); |
| 471 | # endif |
| 472 | } |
| 473 | |
| 474 | template <class String> |
| 475 | String generic_string() const; |
| 476 | |
| 477 | template <class String> |
| 478 | String generic_string(const codecvt_type& cvt) const; |
| 479 | |
| 480 | # ifdef BOOST_WINDOWS_API |
| 481 | const std::string generic_string() const; |
| 482 | const std::string generic_string(const codecvt_type& cvt) const; |
| 483 | const std::wstring generic_wstring() const; |
| 484 | const std::wstring generic_wstring(const codecvt_type&) const { return generic_wstring(); }; |
| 485 | |
| 486 | # else // BOOST_POSIX_API |
| 487 | // On POSIX-like systems, the generic format is the same as the native format |
| 488 | const std::string& generic_string() const { return m_pathname; } |
| 489 | const std::string& generic_string(const codecvt_type&) const { return m_pathname; } |
| 490 | const std::wstring generic_wstring() const { return wstring(); } |
| 491 | const std::wstring generic_wstring(const codecvt_type& cvt) const { return wstring(cvt); } |
| 492 | |
| 493 | # endif |
| 494 | |
| 495 | // ----- compare ----- |
| 496 | |
| 497 | int compare(const path& p) const BOOST_NOEXCEPT; // generic, lexicographical |
| 498 | int compare(const std::string& s) const { return compare(path(s)); } |
| 499 | int compare(const value_type* s) const { return compare(path(s)); } |
| 500 | |
| 501 | // ----- decomposition ----- |
| 502 | |
| 503 | path root_path() const; |
| 504 | path root_name() const; // returns 0 or 1 element path |
| 505 | // even on POSIX, root_name() is non-empty() for network paths |
| 506 | path root_directory() const; // returns 0 or 1 element path |
| 507 | path relative_path() const; |
| 508 | path parent_path() const; |
| 509 | path filename() const; // returns 0 or 1 element path |
| 510 | path stem() const; // returns 0 or 1 element path |
| 511 | path extension() const; // returns 0 or 1 element path |
| 512 | |
| 513 | // ----- query ----- |
| 514 | |
| 515 | bool empty() const BOOST_NOEXCEPT{ return m_pathname.empty(); } |
| 516 | bool filename_is_dot() const; |
| 517 | bool filename_is_dot_dot() const; |
| 518 | bool has_root_path() const { return has_root_directory() || has_root_name(); } |
| 519 | bool has_root_name() const { return !root_name().empty(); } |
| 520 | bool has_root_directory() const { return !root_directory().empty(); } |
| 521 | bool has_relative_path() const { return !relative_path().empty(); } |
| 522 | bool has_parent_path() const { return !parent_path().empty(); } |
| 523 | bool has_filename() const { return !m_pathname.empty(); } |
| 524 | bool has_stem() const { return !stem().empty(); } |
| 525 | bool has_extension() const { return !extension().empty(); } |
| 526 | bool is_relative() const { return !is_absolute(); } |
| 527 | bool is_absolute() const |
| 528 | { |
| 529 | # ifdef BOOST_WINDOWS_API |
| 530 | return has_root_name() && has_root_directory(); |
| 531 | # else |
| 532 | return has_root_directory(); |
| 533 | # endif |
| 534 | } |
| 535 | |
| 536 | // ----- lexical operations ----- |
| 537 | |
| 538 | path lexically_normal() const; |
| 539 | path lexically_relative(const path& base) const; |
| 540 | path lexically_proximate(const path& base) const |
| 541 | { |
| 542 | path tmp(lexically_relative(base)); |
| 543 | return tmp.empty() ? *this : tmp; |
| 544 | } |
| 545 | |
| 546 | // ----- iterators ----- |
| 547 | |
| 548 | class iterator; |
| 549 | typedef iterator const_iterator; |
| 550 | class reverse_iterator; |
| 551 | typedef reverse_iterator const_reverse_iterator; |
| 552 | |
| 553 | iterator begin() const; |
| 554 | iterator end() const; |
| 555 | reverse_iterator rbegin() const; |
| 556 | reverse_iterator rend() const; |
| 557 | |
| 558 | // ----- static member functions ----- |
| 559 | |
| 560 | static std::locale imbue(const std::locale& loc); |
| 561 | static const codecvt_type& codecvt(); |
| 562 | |
| 563 | // ----- deprecated functions ----- |
| 564 | |
| 565 | # if defined(BOOST_FILESYSTEM_DEPRECATED) && defined(BOOST_FILESYSTEM_NO_DEPRECATED) |
| 566 | # error both BOOST_FILESYSTEM_DEPRECATED and BOOST_FILESYSTEM_NO_DEPRECATED are defined |
| 567 | # endif |
| 568 | |
| 569 | # if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) |
| 570 | // recently deprecated functions supplied by default |
| 571 | path& normalize() { |
| 572 | path tmp(lexically_normal()); |
| 573 | m_pathname.swap(tmp.m_pathname); |
| 574 | return *this; |
| 575 | } |
| 576 | path& remove_leaf() { return remove_filename(); } |
| 577 | path leaf() const { return filename(); } |
| 578 | path branch_path() const { return parent_path(); } |
| 579 | path generic() const { return generic_path(); } |
| 580 | bool has_leaf() const { return !m_pathname.empty(); } |
| 581 | bool has_branch_path() const { return !parent_path().empty(); } |
| 582 | bool is_complete() const { return is_absolute(); } |
| 583 | # endif |
| 584 | |
| 585 | # if defined(BOOST_FILESYSTEM_DEPRECATED) |
| 586 | // deprecated functions with enough signature or semantic changes that they are |
| 587 | // not supplied by default |
| 588 | const std::string file_string() const { return string(); } |
| 589 | const std::string directory_string() const { return string(); } |
| 590 | const std::string native_file_string() const { return string(); } |
| 591 | const std::string native_directory_string() const { return string(); } |
| 592 | const string_type external_file_string() const { return native(); } |
| 593 | const string_type external_directory_string() const { return native(); } |
| 594 | |
| 595 | // older functions no longer supported |
| 596 | //typedef bool (*name_check)(const std::string & name); |
| 597 | //basic_path(const string_type& str, name_check) { operator/=(str); } |
| 598 | //basic_path(const typename string_type::value_type* s, name_check) |
| 599 | // { operator/=(s);} |
| 600 | //static bool default_name_check_writable() { return false; } |
| 601 | //static void default_name_check(name_check) {} |
| 602 | //static name_check default_name_check() { return 0; } |
| 603 | //basic_path& canonize(); |
| 604 | # endif |
| 605 | |
| 606 | //--------------------------------------------------------------------------------------// |
| 607 | // class path private members // |
| 608 | //--------------------------------------------------------------------------------------// |
| 609 | |
| 610 | private: |
| 611 | |
| 612 | # if defined(_MSC_VER) |
| 613 | # pragma warning(push) // Save warning settings |
| 614 | # pragma warning(disable : 4251) // disable warning: class 'std::basic_string<_Elem,_Traits,_Ax>' |
| 615 | # endif // needs to have dll-interface... |
| 616 | /* |
| 617 | m_pathname has the type, encoding, and format required by the native |
| 618 | operating system. Thus for POSIX and Windows there is no conversion for |
| 619 | passing m_pathname.c_str() to the O/S API or when obtaining a path from the |
| 620 | O/S API. POSIX encoding is unspecified other than for dot and slash |
| 621 | characters; POSIX just treats paths as a sequence of bytes. Windows |
| 622 | encoding is UCS-2 or UTF-16 depending on the version. |
| 623 | */ |
| 624 | string_type m_pathname; // Windows: as input; backslashes NOT converted to slashes, |
| 625 | // slashes NOT converted to backslashes |
| 626 | # if defined(_MSC_VER) |
| 627 | # pragma warning(pop) // restore warning settings. |
| 628 | # endif |
| 629 | |
| 630 | string_type::size_type m_append_separator_if_needed(); |
| 631 | // Returns: If separator is to be appended, m_pathname.size() before append. Otherwise 0. |
| 632 | // Note: An append is never performed if size()==0, so a returned 0 is unambiguous. |
| 633 | |
| 634 | void m_erase_redundant_separator(string_type::size_type sep_pos); |
| 635 | string_type::size_type m_parent_path_end() const; |
| 636 | |
| 637 | path& m_normalize(); |
| 638 | |
| 639 | // Was qualified; como433beta8 reports: |
| 640 | // warning #427-D: qualified name is not allowed in member declaration |
| 641 | friend class iterator; |
| 642 | friend bool operator<(const path& lhs, const path& rhs); |
| 643 | |
| 644 | // see path::iterator::increment/decrement comment below |
| 645 | static void m_path_iterator_increment(path::iterator & it); |
| 646 | static void m_path_iterator_decrement(path::iterator & it); |
| 647 | |
| 648 | }; // class path |
| 649 | |
| 650 | namespace detail |
| 651 | { |
| 652 | BOOST_FILESYSTEM_DECL |
| 653 | int lex_compare(path::iterator first1, path::iterator last1, |
| 654 | path::iterator first2, path::iterator last2); |
| 655 | BOOST_FILESYSTEM_DECL |
| 656 | const path& dot_path(); |
| 657 | BOOST_FILESYSTEM_DECL |
| 658 | const path& dot_dot_path(); |
| 659 | } |
| 660 | |
| 661 | # ifndef BOOST_FILESYSTEM_NO_DEPRECATED |
| 662 | typedef path wpath; |
| 663 | # endif |
| 664 | |
| 665 | //------------------------------------------------------------------------------------// |
| 666 | // class path::iterator // |
| 667 | //------------------------------------------------------------------------------------// |
| 668 | |
| 669 | class path::iterator |
| 670 | : public boost::iterator_facade< |
| 671 | path::iterator, |
| 672 | path const, |
| 673 | boost::bidirectional_traversal_tag > |
| 674 | { |
| 675 | private: |
| 676 | friend class boost::iterator_core_access; |
| 677 | friend class boost::filesystem::path; |
| 678 | friend class boost::filesystem::path::reverse_iterator; |
| 679 | friend void m_path_iterator_increment(path::iterator & it); |
| 680 | friend void m_path_iterator_decrement(path::iterator & it); |
| 681 | |
| 682 | const path& dereference() const { return m_element; } |
| 683 | |
| 684 | bool equal(const iterator & rhs) const |
| 685 | { |
| 686 | return m_path_ptr == rhs.m_path_ptr && m_pos == rhs.m_pos; |
| 687 | } |
| 688 | |
| 689 | // iterator_facade derived classes don't seem to like implementations in |
| 690 | // separate translation unit dll's, so forward to class path static members |
| 691 | void increment() { m_path_iterator_increment(*this); } |
| 692 | void decrement() { m_path_iterator_decrement(*this); } |
| 693 | |
| 694 | path m_element; // current element |
| 695 | const path* m_path_ptr; // path being iterated over |
| 696 | string_type::size_type m_pos; // position of m_element in |
| 697 | // m_path_ptr->m_pathname. |
| 698 | // if m_element is implicit dot, m_pos is the |
| 699 | // position of the last separator in the path. |
| 700 | // end() iterator is indicated by |
| 701 | // m_pos == m_path_ptr->m_pathname.size() |
| 702 | }; // path::iterator |
| 703 | |
| 704 | //------------------------------------------------------------------------------------// |
| 705 | // class path::reverse_iterator // |
| 706 | //------------------------------------------------------------------------------------// |
| 707 | |
| 708 | class path::reverse_iterator |
| 709 | : public boost::iterator_facade< |
| 710 | path::reverse_iterator, |
| 711 | path const, |
| 712 | boost::bidirectional_traversal_tag > |
| 713 | { |
| 714 | public: |
| 715 | |
| 716 | explicit reverse_iterator(iterator itr) : m_itr(itr) |
| 717 | { |
| 718 | if (itr != itr.m_path_ptr->begin()) |
| 719 | m_element = *--itr; |
| 720 | } |
| 721 | private: |
| 722 | friend class boost::iterator_core_access; |
| 723 | friend class boost::filesystem::path; |
| 724 | |
| 725 | const path& dereference() const { return m_element; } |
| 726 | bool equal(const reverse_iterator& rhs) const { return m_itr == rhs.m_itr; } |
| 727 | void increment() |
| 728 | { |
| 729 | --m_itr; |
| 730 | if (m_itr != m_itr.m_path_ptr->begin()) |
| 731 | { |
| 732 | iterator tmp = m_itr; |
| 733 | m_element = *--tmp; |
| 734 | } |
| 735 | } |
| 736 | void decrement() |
| 737 | { |
| 738 | m_element = *m_itr; |
| 739 | ++m_itr; |
| 740 | } |
| 741 | |
| 742 | iterator m_itr; |
| 743 | path m_element; |
| 744 | |
| 745 | }; // path::reverse_iterator |
| 746 | |
| 747 | //------------------------------------------------------------------------------------// |
| 748 | // // |
| 749 | // non-member functions // |
| 750 | // // |
| 751 | //------------------------------------------------------------------------------------// |
| 752 | |
| 753 | // std::lexicographical_compare would infinately recurse because path iterators |
| 754 | // yield paths, so provide a path aware version |
| 755 | inline bool lexicographical_compare(path::iterator first1, path::iterator last1, |
| 756 | path::iterator first2, path::iterator last2) |
| 757 | { return detail::lex_compare(first1, last1, first2, last2) < 0; } |
| 758 | |
| 759 | inline bool operator==(const path& lhs, const path& rhs) {return lhs.compare(rhs) == 0;} |
| 760 | inline bool operator==(const path& lhs, const path::string_type& rhs) {return lhs.compare(rhs) == 0;} |
| 761 | inline bool operator==(const path::string_type& lhs, const path& rhs) {return rhs.compare(lhs) == 0;} |
| 762 | inline bool operator==(const path& lhs, const path::value_type* rhs) {return lhs.compare(rhs) == 0;} |
| 763 | inline bool operator==(const path::value_type* lhs, const path& rhs) {return rhs.compare(lhs) == 0;} |
| 764 | |
| 765 | inline bool operator!=(const path& lhs, const path& rhs) {return lhs.compare(rhs) != 0;} |
| 766 | inline bool operator!=(const path& lhs, const path::string_type& rhs) {return lhs.compare(rhs) != 0;} |
| 767 | inline bool operator!=(const path::string_type& lhs, const path& rhs) {return rhs.compare(lhs) != 0;} |
| 768 | inline bool operator!=(const path& lhs, const path::value_type* rhs) {return lhs.compare(rhs) != 0;} |
| 769 | inline bool operator!=(const path::value_type* lhs, const path& rhs) {return rhs.compare(lhs) != 0;} |
| 770 | |
| 771 | // TODO: why do == and != have additional overloads, but the others don't? |
| 772 | |
| 773 | inline bool operator<(const path& lhs, const path& rhs) {return lhs.compare(rhs) < 0;} |
| 774 | inline bool operator<=(const path& lhs, const path& rhs) {return !(rhs < lhs);} |
| 775 | inline bool operator> (const path& lhs, const path& rhs) {return rhs < lhs;} |
| 776 | inline bool operator>=(const path& lhs, const path& rhs) {return !(lhs < rhs);} |
| 777 | |
| 778 | inline std::size_t hash_value(const path& x) |
| 779 | { |
| 780 | # ifdef BOOST_WINDOWS_API |
| 781 | std::size_t seed = 0; |
| 782 | for(const path::value_type* it = x.c_str(); *it; ++it) |
| 783 | hash_combine(seed, *it == '/' ? L'\\' : *it); |
| 784 | return seed; |
| 785 | # else // BOOST_POSIX_API |
| 786 | return hash_range(x.native().begin(), x.native().end()); |
| 787 | # endif |
| 788 | } |
| 789 | |
| 790 | inline void swap(path& lhs, path& rhs) { lhs.swap(rhs); } |
| 791 | |
| 792 | inline path operator/(const path& lhs, const path& rhs) { return path(lhs) /= rhs; } |
| 793 | |
| 794 | // inserters and extractors |
| 795 | // use boost::io::quoted() to handle spaces in paths |
| 796 | // use '&' as escape character to ease use for Windows paths |
| 797 | |
| 798 | template <class Char, class Traits> |
| 799 | inline std::basic_ostream<Char, Traits>& |
| 800 | operator<<(std::basic_ostream<Char, Traits>& os, const path& p) |
| 801 | { |
| 802 | return os |
| 803 | << boost::io::quoted(p.template string<std::basic_string<Char> >(), static_cast<Char>('&')); |
| 804 | } |
| 805 | |
| 806 | template <class Char, class Traits> |
| 807 | inline std::basic_istream<Char, Traits>& |
| 808 | operator>>(std::basic_istream<Char, Traits>& is, path& p) |
| 809 | { |
| 810 | std::basic_string<Char> str; |
| 811 | is >> boost::io::quoted(str, static_cast<Char>('&')); |
| 812 | p = str; |
| 813 | return is; |
| 814 | } |
| 815 | |
| 816 | // name_checks |
| 817 | |
| 818 | // These functions are holdovers from version 1. It isn't clear they have much |
| 819 | // usefulness, or how to generalize them for later versions. |
| 820 | |
| 821 | BOOST_FILESYSTEM_DECL bool portable_posix_name(const std::string & name); |
| 822 | BOOST_FILESYSTEM_DECL bool windows_name(const std::string & name); |
| 823 | BOOST_FILESYSTEM_DECL bool portable_name(const std::string & name); |
| 824 | BOOST_FILESYSTEM_DECL bool portable_directory_name(const std::string & name); |
| 825 | BOOST_FILESYSTEM_DECL bool portable_file_name(const std::string & name); |
| 826 | BOOST_FILESYSTEM_DECL bool native(const std::string & name); |
| 827 | |
| 828 | namespace detail |
| 829 | { |
| 830 | // For POSIX, is_directory_separator() and is_element_separator() are identical since |
| 831 | // a forward slash is the only valid directory separator and also the only valid |
| 832 | // element separator. For Windows, forward slash and back slash are the possible |
| 833 | // directory separators, but colon (example: "c:foo") is also an element separator. |
| 834 | |
| 835 | inline bool is_directory_separator(path::value_type c) BOOST_NOEXCEPT |
| 836 | { |
| 837 | return c == path::separator |
| 838 | # ifdef BOOST_WINDOWS_API |
| 839 | || c == path::preferred_separator |
| 840 | # endif |
| 841 | ; |
| 842 | } |
| 843 | inline bool is_element_separator(path::value_type c) BOOST_NOEXCEPT |
| 844 | { |
| 845 | return c == path::separator |
| 846 | # ifdef BOOST_WINDOWS_API |
| 847 | || c == path::preferred_separator || c == L':' |
| 848 | # endif |
| 849 | ; |
| 850 | } |
| 851 | } // namespace detail |
| 852 | |
| 853 | //------------------------------------------------------------------------------------// |
| 854 | // class path miscellaneous function implementations // |
| 855 | //------------------------------------------------------------------------------------// |
| 856 | |
| 857 | inline path::reverse_iterator path::rbegin() const { return reverse_iterator(end()); } |
| 858 | inline path::reverse_iterator path::rend() const { return reverse_iterator(begin()); } |
| 859 | |
| 860 | inline bool path::filename_is_dot() const |
| 861 | { |
| 862 | // implicit dot is tricky, so actually call filename(); see path::filename() example |
| 863 | // in reference.html |
| 864 | path p(filename()); |
| 865 | return p.size() == 1 && *p.c_str() == dot; |
| 866 | } |
| 867 | |
| 868 | inline bool path::filename_is_dot_dot() const |
| 869 | { |
| 870 | return size() >= 2 && m_pathname[size()-1] == dot && m_pathname[size()-2] == dot |
| 871 | && (m_pathname.size() == 2 || detail::is_element_separator(m_pathname[size()-3])); |
| 872 | // use detail::is_element_separator() rather than detail::is_directory_separator |
| 873 | // to deal with "c:.." edge case on Windows when ':' acts as a separator |
| 874 | } |
| 875 | |
| 876 | //--------------------------------------------------------------------------------------// |
| 877 | // class path member template implementation // |
| 878 | //--------------------------------------------------------------------------------------// |
| 879 | |
| 880 | template <class InputIterator> |
| 881 | path& path::append(InputIterator begin, InputIterator end) |
| 882 | { |
| 883 | if (begin == end) |
| 884 | return *this; |
| 885 | string_type::size_type sep_pos(m_append_separator_if_needed()); |
| 886 | std::basic_string<typename std::iterator_traits<InputIterator>::value_type> |
| 887 | seq(begin, end); |
| 888 | path_traits::convert(seq.c_str(), seq.c_str()+seq.size(), m_pathname); |
| 889 | if (sep_pos) |
| 890 | m_erase_redundant_separator(sep_pos); |
| 891 | return *this; |
| 892 | } |
| 893 | |
| 894 | template <class InputIterator> |
| 895 | path& path::append(InputIterator begin, InputIterator end, const codecvt_type& cvt) |
| 896 | { |
| 897 | if (begin == end) |
| 898 | return *this; |
| 899 | string_type::size_type sep_pos(m_append_separator_if_needed()); |
| 900 | std::basic_string<typename std::iterator_traits<InputIterator>::value_type> |
| 901 | seq(begin, end); |
| 902 | path_traits::convert(seq.c_str(), seq.c_str()+seq.size(), m_pathname, cvt); |
| 903 | if (sep_pos) |
| 904 | m_erase_redundant_separator(sep_pos); |
| 905 | return *this; |
| 906 | } |
| 907 | |
| 908 | template <class Source> |
| 909 | path& path::append(Source const& source) |
| 910 | { |
| 911 | if (path_traits::empty(source)) |
| 912 | return *this; |
| 913 | string_type::size_type sep_pos(m_append_separator_if_needed()); |
| 914 | path_traits::dispatch(source, m_pathname); |
| 915 | if (sep_pos) |
| 916 | m_erase_redundant_separator(sep_pos); |
| 917 | return *this; |
| 918 | } |
| 919 | |
| 920 | template <class Source> |
| 921 | path& path::append(Source const& source, const codecvt_type& cvt) |
| 922 | { |
| 923 | if (path_traits::empty(source)) |
| 924 | return *this; |
| 925 | string_type::size_type sep_pos(m_append_separator_if_needed()); |
| 926 | path_traits::dispatch(source, m_pathname, cvt); |
| 927 | if (sep_pos) |
| 928 | m_erase_redundant_separator(sep_pos); |
| 929 | return *this; |
| 930 | } |
| 931 | |
| 932 | //--------------------------------------------------------------------------------------// |
| 933 | // class path member template specializations // |
| 934 | //--------------------------------------------------------------------------------------// |
| 935 | |
| 936 | template <> inline |
| 937 | std::string path::string<std::string>() const |
| 938 | { return string(); } |
| 939 | |
| 940 | template <> inline |
| 941 | std::wstring path::string<std::wstring>() const |
| 942 | { return wstring(); } |
| 943 | |
| 944 | template <> inline |
| 945 | std::string path::string<std::string>(const codecvt_type& cvt) const |
| 946 | { return string(cvt); } |
| 947 | |
| 948 | template <> inline |
| 949 | std::wstring path::string<std::wstring>(const codecvt_type& cvt) const |
| 950 | { return wstring(cvt); } |
| 951 | |
| 952 | template <> inline |
| 953 | std::string path::generic_string<std::string>() const |
| 954 | { return generic_string(); } |
| 955 | |
| 956 | template <> inline |
| 957 | std::wstring path::generic_string<std::wstring>() const |
| 958 | { return generic_wstring(); } |
| 959 | |
| 960 | template <> inline |
| 961 | std::string path::generic_string<std::string>(const codecvt_type& cvt) const |
| 962 | { return generic_string(cvt); } |
| 963 | |
| 964 | template <> inline |
| 965 | std::wstring path::generic_string<std::wstring>(const codecvt_type& cvt) const |
| 966 | { return generic_wstring(cvt); } |
| 967 | |
| 968 | //--------------------------------------------------------------------------------------// |
| 969 | // path_traits convert function implementations // |
| 970 | // requiring path::codecvt() be visable // |
| 971 | //--------------------------------------------------------------------------------------// |
| 972 | |
| 973 | namespace path_traits |
| 974 | { // without codecvt |
| 975 | |
| 976 | inline |
| 977 | void convert(const char* from, |
| 978 | const char* from_end, // 0 for null terminated MBCS |
| 979 | std::wstring & to) |
| 980 | { |
| 981 | convert(from, from_end, to, path::codecvt()); |
| 982 | } |
| 983 | |
| 984 | inline |
| 985 | void convert(const wchar_t* from, |
| 986 | const wchar_t* from_end, // 0 for null terminated MBCS |
| 987 | std::string & to) |
| 988 | { |
| 989 | convert(from, from_end, to, path::codecvt()); |
| 990 | } |
| 991 | |
| 992 | inline |
| 993 | void convert(const char* from, |
| 994 | std::wstring & to) |
| 995 | { |
| 996 | BOOST_ASSERT(from); |
| 997 | convert(from, 0, to, path::codecvt()); |
| 998 | } |
| 999 | |
| 1000 | inline |
| 1001 | void convert(const wchar_t* from, |
| 1002 | std::string & to) |
| 1003 | { |
| 1004 | BOOST_ASSERT(from); |
| 1005 | convert(from, 0, to, path::codecvt()); |
| 1006 | } |
| 1007 | } // namespace path_traits |
| 1008 | } // namespace filesystem |
| 1009 | } // namespace boost |
| 1010 | |
| 1011 | //----------------------------------------------------------------------------// |
| 1012 | |
| 1013 | #include <boost/config/abi_suffix.hpp> // pops abi_prefix.hpp pragmas |
| 1014 | |
| 1015 | #endif // BOOST_FILESYSTEM_PATH_HPP |
| 1016 | |