Jeff Thompson | 86b6d64 | 2013-10-17 15:01:56 -0700 | [diff] [blame] | 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 NDNBOOST_FILESYSTEM_PATH_HPP |
| 16 | #define NDNBOOST_FILESYSTEM_PATH_HPP |
| 17 | |
| 18 | #include <ndnboost/config.hpp> |
| 19 | |
| 20 | # if defined( NDNBOOST_NO_STD_WSTRING ) |
| 21 | # error Configuration not supported: Boost.Filesystem V3 and later requires std::wstring support |
| 22 | # endif |
| 23 | |
| 24 | #include <ndnboost/filesystem/config.hpp> |
| 25 | #include <ndnboost/filesystem/path_traits.hpp> // includes <cwchar> |
| 26 | #include <ndnboost/system/error_code.hpp> |
| 27 | #include <ndnboost/system/system_error.hpp> |
| 28 | #include <ndnboost/iterator/iterator_facade.hpp> |
| 29 | #include <ndnboost/shared_ptr.hpp> |
| 30 | #include <ndnboost/io/detail/quoted_manip.hpp> |
| 31 | #include <ndnboost/static_assert.hpp> |
| 32 | #include <ndnboost/functional/hash_fwd.hpp> |
| 33 | #include <ndnboost/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 <ndnboost/config/abi_prefix.hpp> // must be the last #include |
| 44 | |
| 45 | namespace ndnboost |
| 46 | { |
| 47 | namespace filesystem |
| 48 | { |
| 49 | //------------------------------------------------------------------------------------// |
| 50 | // // |
| 51 | // class path // |
| 52 | // // |
| 53 | //------------------------------------------------------------------------------------// |
| 54 | |
| 55 | class NDNBOOST_FILESYSTEM_DECL path |
| 56 | { |
| 57 | public: |
| 58 | |
| 59 | // value_type is the character type used by the operating system API to |
| 60 | // represent paths. |
| 61 | |
| 62 | # ifdef NDNBOOST_WINDOWS_API |
| 63 | typedef wchar_t value_type; |
| 64 | NDNBOOST_STATIC_CONSTEXPR value_type preferred_separator = L'\\'; |
| 65 | # else |
| 66 | typedef char value_type; |
| 67 | NDNBOOST_STATIC_CONSTEXPR value_type preferred_separator = '/'; |
| 68 | # endif |
| 69 | typedef std::basic_string<value_type> string_type; |
| 70 | typedef std::codecvt<wchar_t, char, |
| 71 | std::mbstate_t> codecvt_type; |
| 72 | |
| 73 | |
| 74 | // ----- character encoding conversions ----- |
| 75 | |
| 76 | // Following the principle of least astonishment, path input arguments |
| 77 | // passed to or obtained from the operating system via objects of |
| 78 | // class path behave as if they were directly passed to or |
| 79 | // obtained from the O/S API, unless conversion is explicitly requested. |
| 80 | // |
| 81 | // POSIX specfies that path strings are passed unchanged to and from the |
| 82 | // API. Note that this is different from the POSIX command line utilities, |
| 83 | // which convert according to a locale. |
| 84 | // |
| 85 | // Thus for POSIX, char strings do not undergo conversion. wchar_t strings |
| 86 | // are converted to/from char using the path locale or, if a conversion |
| 87 | // argument is given, using a conversion object modeled on |
| 88 | // std::wstring_convert. |
| 89 | // |
| 90 | // The path locale, which is global to the thread, can be changed by the |
| 91 | // imbue() function. It is initialized to an implementation defined locale. |
| 92 | // |
| 93 | // For Windows, wchar_t strings do not undergo conversion. char strings |
| 94 | // are converted using the "ANSI" or "OEM" code pages, as determined by |
| 95 | // the AreFileApisANSI() function, or, if a conversion argument is given, |
| 96 | // using a conversion object modeled on std::wstring_convert. |
| 97 | // |
| 98 | // See m_pathname comments for further important rationale. |
| 99 | |
| 100 | // TODO: rules needed for operating systems that use / or . |
| 101 | // differently, or format directory paths differently from file paths. |
| 102 | // |
| 103 | // ********************************************************************************** |
| 104 | // |
| 105 | // More work needed: How to handle an operating system that may have |
| 106 | // slash characters or dot characters in valid filenames, either because |
| 107 | // it doesn't follow the POSIX standard, or because it allows MBCS |
| 108 | // filename encodings that may contain slash or dot characters. For |
| 109 | // example, ISO/IEC 2022 (JIS) encoding which allows switching to |
| 110 | // JIS x0208-1983 encoding. A valid filename in this set of encodings is |
| 111 | // 0x1B 0x24 0x42 [switch to X0208-1983] 0x24 0x2F [U+304F Kiragana letter KU] |
| 112 | // ^^^^ |
| 113 | // Note that 0x2F is the ASCII slash character |
| 114 | // |
| 115 | // ********************************************************************************** |
| 116 | |
| 117 | // Supported source arguments: half-open iterator range, container, c-array, |
| 118 | // and single pointer to null terminated string. |
| 119 | |
| 120 | // All source arguments except pointers to null terminated byte strings support |
| 121 | // multi-byte character strings which may have embedded nulls. Embedded null |
| 122 | // support is required for some Asian languages on Windows. |
| 123 | |
| 124 | // [defaults] "const codecvt_type& cvt=codecvt()" default arguments are not used |
| 125 | // because some compilers, such as Microsoft prior to VC++ 10, do not handle defaults |
| 126 | // correctly in templates. |
| 127 | |
| 128 | // ----- constructors ----- |
| 129 | |
| 130 | path(){} |
| 131 | |
| 132 | path(const path& p) : m_pathname(p.m_pathname) {} |
| 133 | |
| 134 | template <class Source> |
| 135 | path(Source const& source, |
| 136 | typename ndnboost::enable_if<path_traits::is_pathable< |
| 137 | typename ndnboost::decay<Source>::type> >::type* =0) |
| 138 | { |
| 139 | path_traits::dispatch(source, m_pathname, codecvt()); |
| 140 | } |
| 141 | |
| 142 | // Overloads for the operating system API's native character type. Rationale: |
| 143 | // - Avoids use of codecvt() for native value_type strings. This limits the |
| 144 | // impact of locale("") initialization failures on POSIX systems to programs |
| 145 | // that actually depend on locale(""). It further ensures that exceptions thrown |
| 146 | // as a result of such failues occur after main() has started, so can be caught. |
| 147 | // This is a partial resolution of tickets 4688, 5100, and 5289. |
| 148 | // - A slight optimization for a common use case, particularly on POSIX since |
| 149 | // value_type is char and that is the most common useage. |
| 150 | path(const value_type* s) : m_pathname(s) {} |
| 151 | path(const std::basic_string<value_type>& s) : m_pathname(s) {} |
| 152 | |
| 153 | template <class Source> |
| 154 | path(Source const& source, const codecvt_type& cvt) |
| 155 | // see [defaults] note above explaining why codecvt() default arguments are not used |
| 156 | { |
| 157 | path_traits::dispatch(source, m_pathname, cvt); |
| 158 | } |
| 159 | |
| 160 | template <class InputIterator> |
| 161 | path(InputIterator begin, InputIterator end) |
| 162 | { |
| 163 | if (begin != end) |
| 164 | { |
| 165 | std::basic_string<typename std::iterator_traits<InputIterator>::value_type> |
| 166 | s(begin, end); |
| 167 | path_traits::convert(s.c_str(), s.c_str()+s.size(), m_pathname, codecvt()); |
| 168 | } |
| 169 | } |
| 170 | |
| 171 | template <class InputIterator> |
| 172 | path(InputIterator begin, InputIterator end, const codecvt_type& cvt) |
| 173 | { |
| 174 | if (begin != end) |
| 175 | { |
| 176 | std::basic_string<typename std::iterator_traits<InputIterator>::value_type> |
| 177 | s(begin, end); |
| 178 | path_traits::convert(s.c_str(), s.c_str()+s.size(), m_pathname, cvt); |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | // ----- assignments ----- |
| 183 | |
| 184 | path& operator=(const path& p) |
| 185 | { |
| 186 | m_pathname = p.m_pathname; |
| 187 | return *this; |
| 188 | } |
| 189 | |
| 190 | path& operator=(const value_type* ptr) // required in case ptr overlaps *this |
| 191 | { |
| 192 | m_pathname = ptr; |
| 193 | return *this; |
| 194 | } |
| 195 | |
| 196 | template <class Source> |
| 197 | typename ndnboost::enable_if<path_traits::is_pathable< |
| 198 | typename ndnboost::decay<Source>::type>, path&>::type |
| 199 | operator=(Source const& source) |
| 200 | { |
| 201 | m_pathname.clear(); |
| 202 | path_traits::dispatch(source, m_pathname, codecvt()); |
| 203 | return *this; |
| 204 | } |
| 205 | |
| 206 | path& assign(const value_type* ptr, const codecvt_type&) // required in case ptr overlaps *this |
| 207 | { |
| 208 | m_pathname = ptr; |
| 209 | return *this; |
| 210 | } |
| 211 | |
| 212 | template <class Source> |
| 213 | path& assign(Source const& source, const codecvt_type& cvt) |
| 214 | { |
| 215 | m_pathname.clear(); |
| 216 | path_traits::dispatch(source, m_pathname, cvt); |
| 217 | return *this; |
| 218 | } |
| 219 | |
| 220 | template <class InputIterator> |
| 221 | path& assign(InputIterator begin, InputIterator end) |
| 222 | { |
| 223 | return assign(begin, end, codecvt()); |
| 224 | } |
| 225 | |
| 226 | template <class InputIterator> |
| 227 | path& assign(InputIterator begin, InputIterator end, const codecvt_type& cvt) |
| 228 | { |
| 229 | m_pathname.clear(); |
| 230 | if (begin != end) |
| 231 | { |
| 232 | std::basic_string<typename std::iterator_traits<InputIterator>::value_type> |
| 233 | s(begin, end); |
| 234 | path_traits::convert(s.c_str(), s.c_str()+s.size(), m_pathname, cvt); |
| 235 | } |
| 236 | return *this; |
| 237 | } |
| 238 | |
| 239 | // ----- concatenation ----- |
| 240 | |
| 241 | path& operator+=(const path& p) {m_pathname += p.m_pathname; return *this;} |
| 242 | path& operator+=(const string_type& s) {m_pathname += s; return *this;} |
| 243 | path& operator+=(const value_type* ptr) {m_pathname += ptr; return *this;} |
| 244 | path& operator+=(value_type c) {m_pathname += c; return *this;} |
| 245 | |
| 246 | template <class Source> |
| 247 | typename ndnboost::enable_if<path_traits::is_pathable< |
| 248 | typename ndnboost::decay<Source>::type>, path&>::type |
| 249 | operator+=(Source const& source) |
| 250 | { |
| 251 | return concat(source, codecvt()); |
| 252 | } |
| 253 | |
| 254 | template <class CharT> |
| 255 | typename ndnboost::enable_if<is_integral<CharT>, path&>::type |
| 256 | operator+=(CharT c) |
| 257 | { |
| 258 | CharT tmp[2]; |
| 259 | tmp[0] = c; |
| 260 | tmp[1] = 0; |
| 261 | return concat(tmp, codecvt()); |
| 262 | } |
| 263 | |
| 264 | template <class Source> |
| 265 | path& concat(Source const& source, const codecvt_type& cvt) |
| 266 | { |
| 267 | path_traits::dispatch(source, m_pathname, cvt); |
| 268 | return *this; |
| 269 | } |
| 270 | |
| 271 | template <class InputIterator> |
| 272 | path& concat(InputIterator begin, InputIterator end) |
| 273 | { |
| 274 | return concat(begin, end, codecvt()); |
| 275 | } |
| 276 | |
| 277 | template <class InputIterator> |
| 278 | path& concat(InputIterator begin, InputIterator end, const codecvt_type& cvt) |
| 279 | { |
| 280 | if (begin == end) |
| 281 | return *this; |
| 282 | std::basic_string<typename std::iterator_traits<InputIterator>::value_type> |
| 283 | s(begin, end); |
| 284 | path_traits::convert(s.c_str(), s.c_str()+s.size(), m_pathname, cvt); |
| 285 | return *this; |
| 286 | } |
| 287 | |
| 288 | // ----- appends ----- |
| 289 | |
| 290 | // if a separator is added, it is the preferred separator for the platform; |
| 291 | // slash for POSIX, backslash for Windows |
| 292 | |
| 293 | path& operator/=(const path& p); |
| 294 | |
| 295 | path& operator/=(const value_type* ptr); |
| 296 | |
| 297 | template <class Source> |
| 298 | typename ndnboost::enable_if<path_traits::is_pathable< |
| 299 | typename ndnboost::decay<Source>::type>, path&>::type |
| 300 | operator/=(Source const& source) |
| 301 | { |
| 302 | return append(source, codecvt()); |
| 303 | } |
| 304 | |
| 305 | path& append(const value_type* ptr, const codecvt_type&) // required in case ptr overlaps *this |
| 306 | { |
| 307 | this->operator/=(ptr); |
| 308 | return *this; |
| 309 | } |
| 310 | |
| 311 | template <class Source> |
| 312 | path& append(Source const& source, const codecvt_type& cvt); |
| 313 | |
| 314 | template <class InputIterator> |
| 315 | path& append(InputIterator begin, InputIterator end) |
| 316 | { |
| 317 | return append(begin, end, codecvt()); |
| 318 | } |
| 319 | |
| 320 | template <class InputIterator> |
| 321 | path& append(InputIterator begin, InputIterator end, const codecvt_type& cvt); |
| 322 | |
| 323 | // ----- modifiers ----- |
| 324 | |
| 325 | void clear() { m_pathname.clear(); } |
| 326 | path& make_preferred() |
| 327 | # ifdef NDNBOOST_POSIX_API |
| 328 | { return *this; } // POSIX no effect |
| 329 | # else // NDNBOOST_WINDOWS_API |
| 330 | ; // change slashes to backslashes |
| 331 | # endif |
| 332 | path& remove_filename(); |
| 333 | path& replace_extension(const path& new_extension = path()); |
| 334 | void swap(path& rhs) { m_pathname.swap(rhs.m_pathname); } |
| 335 | |
| 336 | // ----- observers ----- |
| 337 | |
| 338 | // For operating systems that format file paths differently than directory |
| 339 | // paths, return values from observers are formatted as file names unless there |
| 340 | // is a trailing separator, in which case returns are formatted as directory |
| 341 | // paths. POSIX and Windows make no such distinction. |
| 342 | |
| 343 | // Implementations are permitted to return const values or const references. |
| 344 | |
| 345 | // The string or path returned by an observer are specified as being formatted |
| 346 | // as "native" or "generic". |
| 347 | // |
| 348 | // For POSIX, these are all the same format; slashes and backslashes are as input and |
| 349 | // are not modified. |
| 350 | // |
| 351 | // For Windows, native: as input; slashes and backslashes are not modified; |
| 352 | // this is the format of the internally stored string. |
| 353 | // generic: backslashes are converted to slashes |
| 354 | |
| 355 | // ----- native format observers ----- |
| 356 | |
| 357 | const string_type& native() const { return m_pathname; } // Throws: nothing |
| 358 | const value_type* c_str() const { return m_pathname.c_str(); } // Throws: nothing |
| 359 | |
| 360 | template <class String> |
| 361 | String string() const; |
| 362 | |
| 363 | template <class String> |
| 364 | String string(const codecvt_type& cvt) const; |
| 365 | |
| 366 | # ifdef NDNBOOST_WINDOWS_API |
| 367 | const std::string string() const { return string(codecvt()); } |
| 368 | const std::string string(const codecvt_type& cvt) const |
| 369 | { |
| 370 | std::string tmp; |
| 371 | if (!m_pathname.empty()) |
| 372 | path_traits::convert(&*m_pathname.begin(), &*m_pathname.begin()+m_pathname.size(), |
| 373 | tmp, cvt); |
| 374 | return tmp; |
| 375 | } |
| 376 | |
| 377 | // string_type is std::wstring, so there is no conversion |
| 378 | const std::wstring& wstring() const { return m_pathname; } |
| 379 | const std::wstring& wstring(const codecvt_type&) const { return m_pathname; } |
| 380 | |
| 381 | # else // NDNBOOST_POSIX_API |
| 382 | // string_type is std::string, so there is no conversion |
| 383 | const std::string& string() const { return m_pathname; } |
| 384 | const std::string& string(const codecvt_type&) const { return m_pathname; } |
| 385 | |
| 386 | const std::wstring wstring() const { return wstring(codecvt()); } |
| 387 | const std::wstring wstring(const codecvt_type& cvt) const |
| 388 | { |
| 389 | std::wstring tmp; |
| 390 | if (!m_pathname.empty()) |
| 391 | path_traits::convert(&*m_pathname.begin(), &*m_pathname.begin()+m_pathname.size(), |
| 392 | tmp, cvt); |
| 393 | return tmp; |
| 394 | } |
| 395 | |
| 396 | # endif |
| 397 | |
| 398 | // ----- generic format observers ----- |
| 399 | |
| 400 | template <class String> |
| 401 | String generic_string() const; |
| 402 | |
| 403 | template <class String> |
| 404 | String generic_string(const codecvt_type& cvt) const; |
| 405 | |
| 406 | # ifdef NDNBOOST_WINDOWS_API |
| 407 | const std::string generic_string() const { return generic_string(codecvt()); } |
| 408 | const std::string generic_string(const codecvt_type& cvt) const; |
| 409 | const std::wstring generic_wstring() const; |
| 410 | const std::wstring generic_wstring(const codecvt_type&) const { return generic_wstring(); }; |
| 411 | |
| 412 | # else // NDNBOOST_POSIX_API |
| 413 | // On POSIX-like systems, the generic format is the same as the native format |
| 414 | const std::string& generic_string() const { return m_pathname; } |
| 415 | const std::string& generic_string(const codecvt_type&) const { return m_pathname; } |
| 416 | const std::wstring generic_wstring() const { return wstring(codecvt()); } |
| 417 | const std::wstring generic_wstring(const codecvt_type& cvt) const { return wstring(cvt); } |
| 418 | |
| 419 | # endif |
| 420 | |
| 421 | // ----- compare ----- |
| 422 | |
| 423 | int compare(const path& p) const NDNBOOST_NOEXCEPT; // generic, lexicographical |
| 424 | int compare(const std::string& s) const { return compare(path(s)); } |
| 425 | int compare(const value_type* s) const { return compare(path(s)); } |
| 426 | |
| 427 | // ----- decomposition ----- |
| 428 | |
| 429 | path root_path() const; |
| 430 | path root_name() const; // returns 0 or 1 element path |
| 431 | // even on POSIX, root_name() is non-empty() for network paths |
| 432 | path root_directory() const; // returns 0 or 1 element path |
| 433 | path relative_path() const; |
| 434 | path parent_path() const; |
| 435 | path filename() const; // returns 0 or 1 element path |
| 436 | path stem() const; // returns 0 or 1 element path |
| 437 | path extension() const; // returns 0 or 1 element path |
| 438 | |
| 439 | // ----- query ----- |
| 440 | |
| 441 | bool empty() const { return m_pathname.empty(); } // name consistent with std containers |
| 442 | bool has_root_path() const { return has_root_directory() || has_root_name(); } |
| 443 | bool has_root_name() const { return !root_name().empty(); } |
| 444 | bool has_root_directory() const { return !root_directory().empty(); } |
| 445 | bool has_relative_path() const { return !relative_path().empty(); } |
| 446 | bool has_parent_path() const { return !parent_path().empty(); } |
| 447 | bool has_filename() const { return !m_pathname.empty(); } |
| 448 | bool has_stem() const { return !stem().empty(); } |
| 449 | bool has_extension() const { return !extension().empty(); } |
| 450 | bool is_absolute() const |
| 451 | { |
| 452 | # ifdef NDNBOOST_WINDOWS_API |
| 453 | return has_root_name() && has_root_directory(); |
| 454 | # else |
| 455 | return has_root_directory(); |
| 456 | # endif |
| 457 | } |
| 458 | bool is_relative() const { return !is_absolute(); } |
| 459 | |
| 460 | // ----- iterators ----- |
| 461 | |
| 462 | class iterator; |
| 463 | typedef iterator const_iterator; |
| 464 | |
| 465 | iterator begin() const; |
| 466 | iterator end() const; |
| 467 | |
| 468 | // ----- static member functions ----- |
| 469 | |
| 470 | static std::locale imbue(const std::locale& loc); |
| 471 | static const codecvt_type& codecvt(); |
| 472 | |
| 473 | // ----- deprecated functions ----- |
| 474 | |
| 475 | # if defined(NDNBOOST_FILESYSTEM_DEPRECATED) && defined(NDNBOOST_FILESYSTEM_NO_DEPRECATED) |
| 476 | # error both NDNBOOST_FILESYSTEM_DEPRECATED and NDNBOOST_FILESYSTEM_NO_DEPRECATED are defined |
| 477 | # endif |
| 478 | |
| 479 | # if !defined(NDNBOOST_FILESYSTEM_NO_DEPRECATED) |
| 480 | // recently deprecated functions supplied by default |
| 481 | path& normalize() { return m_normalize(); } |
| 482 | path& remove_leaf() { return remove_filename(); } |
| 483 | path leaf() const { return filename(); } |
| 484 | path branch_path() const { return parent_path(); } |
| 485 | bool has_leaf() const { return !m_pathname.empty(); } |
| 486 | bool has_branch_path() const { return !parent_path().empty(); } |
| 487 | bool is_complete() const { return is_absolute(); } |
| 488 | # endif |
| 489 | |
| 490 | # if defined(NDNBOOST_FILESYSTEM_DEPRECATED) |
| 491 | // deprecated functions with enough signature or semantic changes that they are |
| 492 | // not supplied by default |
| 493 | const std::string file_string() const { return string(); } |
| 494 | const std::string directory_string() const { return string(); } |
| 495 | const std::string native_file_string() const { return string(); } |
| 496 | const std::string native_directory_string() const { return string(); } |
| 497 | const string_type external_file_string() const { return native(); } |
| 498 | const string_type external_directory_string() const { return native(); } |
| 499 | |
| 500 | // older functions no longer supported |
| 501 | //typedef bool (*name_check)(const std::string & name); |
| 502 | //basic_path(const string_type& str, name_check) { operator/=(str); } |
| 503 | //basic_path(const typename string_type::value_type* s, name_check) |
| 504 | // { operator/=(s);} |
| 505 | //static bool default_name_check_writable() { return false; } |
| 506 | //static void default_name_check(name_check) {} |
| 507 | //static name_check default_name_check() { return 0; } |
| 508 | //basic_path& canonize(); |
| 509 | # endif |
| 510 | |
| 511 | //--------------------------------------------------------------------------------------// |
| 512 | // class path private members // |
| 513 | //--------------------------------------------------------------------------------------// |
| 514 | |
| 515 | private: |
| 516 | # if defined(_MSC_VER) |
| 517 | # pragma warning(push) // Save warning settings |
| 518 | # pragma warning(disable : 4251) // disable warning: class 'std::basic_string<_Elem,_Traits,_Ax>' |
| 519 | # endif // needs to have dll-interface... |
| 520 | /* |
| 521 | m_pathname has the type, encoding, and format required by the native |
| 522 | operating system. Thus for POSIX and Windows there is no conversion for |
| 523 | passing m_pathname.c_str() to the O/S API or when obtaining a path from the |
| 524 | O/S API. POSIX encoding is unspecified other than for dot and slash |
| 525 | characters; POSIX just treats paths as a sequence of bytes. Windows |
| 526 | encoding is UCS-2 or UTF-16 depending on the version. |
| 527 | */ |
| 528 | string_type m_pathname; // Windows: as input; backslashes NOT converted to slashes, |
| 529 | // slashes NOT converted to backslashes |
| 530 | # if defined(_MSC_VER) |
| 531 | # pragma warning(pop) // restore warning settings. |
| 532 | # endif |
| 533 | |
| 534 | string_type::size_type m_append_separator_if_needed(); |
| 535 | // Returns: If separator is to be appended, m_pathname.size() before append. Otherwise 0. |
| 536 | // Note: An append is never performed if size()==0, so a returned 0 is unambiguous. |
| 537 | |
| 538 | void m_erase_redundant_separator(string_type::size_type sep_pos); |
| 539 | string_type::size_type m_parent_path_end() const; |
| 540 | |
| 541 | path& m_normalize(); |
| 542 | |
| 543 | // Was qualified; como433beta8 reports: |
| 544 | // warning #427-D: qualified name is not allowed in member declaration |
| 545 | friend class iterator; |
| 546 | friend bool operator<(const path& lhs, const path& rhs); |
| 547 | |
| 548 | // see path::iterator::increment/decrement comment below |
| 549 | static void m_path_iterator_increment(path::iterator & it); |
| 550 | static void m_path_iterator_decrement(path::iterator & it); |
| 551 | |
| 552 | }; // class path |
| 553 | |
| 554 | namespace detail |
| 555 | { |
| 556 | NDNBOOST_FILESYSTEM_DECL |
| 557 | int lex_compare(path::iterator first1, path::iterator last1, |
| 558 | path::iterator first2, path::iterator last2); |
| 559 | } |
| 560 | |
| 561 | # ifndef NDNBOOST_FILESYSTEM_NO_DEPRECATED |
| 562 | typedef path wpath; |
| 563 | # endif |
| 564 | |
| 565 | //------------------------------------------------------------------------------------// |
| 566 | // class path::iterator // |
| 567 | //------------------------------------------------------------------------------------// |
| 568 | |
| 569 | class path::iterator |
| 570 | : public ndnboost::iterator_facade< |
| 571 | path::iterator, |
| 572 | path const, |
| 573 | ndnboost::bidirectional_traversal_tag > |
| 574 | { |
| 575 | private: |
| 576 | friend class ndnboost::iterator_core_access; |
| 577 | friend class ndnboost::filesystem::path; |
| 578 | friend void m_path_iterator_increment(path::iterator & it); |
| 579 | friend void m_path_iterator_decrement(path::iterator & it); |
| 580 | |
| 581 | const path& dereference() const { return m_element; } |
| 582 | |
| 583 | bool equal(const iterator & rhs) const |
| 584 | { |
| 585 | return m_path_ptr == rhs.m_path_ptr && m_pos == rhs.m_pos; |
| 586 | } |
| 587 | |
| 588 | // iterator_facade derived classes don't seem to like implementations in |
| 589 | // separate translation unit dll's, so forward to class path static members |
| 590 | void increment() { m_path_iterator_increment(*this); } |
| 591 | void decrement() { m_path_iterator_decrement(*this); } |
| 592 | |
| 593 | path m_element; // current element |
| 594 | const path* m_path_ptr; // path being iterated over |
| 595 | string_type::size_type m_pos; // position of m_element in |
| 596 | // m_path_ptr->m_pathname. |
| 597 | // if m_element is implicit dot, m_pos is the |
| 598 | // position of the last separator in the path. |
| 599 | // end() iterator is indicated by |
| 600 | // m_pos == m_path_ptr->m_pathname.size() |
| 601 | }; // path::iterator |
| 602 | |
| 603 | //------------------------------------------------------------------------------------// |
| 604 | // // |
| 605 | // non-member functions // |
| 606 | // // |
| 607 | //------------------------------------------------------------------------------------// |
| 608 | |
| 609 | // std::lexicographical_compare would infinately recurse because path iterators |
| 610 | // yield paths, so provide a path aware version |
| 611 | inline bool lexicographical_compare(path::iterator first1, path::iterator last1, |
| 612 | path::iterator first2, path::iterator last2) |
| 613 | { return detail::lex_compare(first1, last1, first2, last2) < 0; } |
| 614 | |
| 615 | inline bool operator==(const path& lhs, const path& rhs) {return lhs.compare(rhs) == 0;} |
| 616 | inline bool operator==(const path& lhs, const path::string_type& rhs) {return lhs.compare(rhs) == 0;} |
| 617 | inline bool operator==(const path::string_type& lhs, const path& rhs) {return rhs.compare(lhs) == 0;} |
| 618 | inline bool operator==(const path& lhs, const path::value_type* rhs) {return lhs.compare(rhs) == 0;} |
| 619 | inline bool operator==(const path::value_type* lhs, const path& rhs) {return rhs.compare(lhs) == 0;} |
| 620 | |
| 621 | inline bool operator!=(const path& lhs, const path& rhs) {return lhs.compare(rhs) != 0;} |
| 622 | inline bool operator!=(const path& lhs, const path::string_type& rhs) {return lhs.compare(rhs) != 0;} |
| 623 | inline bool operator!=(const path::string_type& lhs, const path& rhs) {return rhs.compare(lhs) != 0;} |
| 624 | inline bool operator!=(const path& lhs, const path::value_type* rhs) {return lhs.compare(rhs) != 0;} |
| 625 | inline bool operator!=(const path::value_type* lhs, const path& rhs) {return rhs.compare(lhs) != 0;} |
| 626 | |
| 627 | // TODO: why do == and != have additional overloads, but the others don't? |
| 628 | |
| 629 | inline bool operator<(const path& lhs, const path& rhs) {return lhs.compare(rhs) < 0;} |
| 630 | inline bool operator<=(const path& lhs, const path& rhs) {return !(rhs < lhs);} |
| 631 | inline bool operator> (const path& lhs, const path& rhs) {return rhs < lhs;} |
| 632 | inline bool operator>=(const path& lhs, const path& rhs) {return !(lhs < rhs);} |
| 633 | |
| 634 | inline std::size_t hash_value(const path& x) |
| 635 | { |
| 636 | # ifdef NDNBOOST_WINDOWS_API |
| 637 | std::size_t seed = 0; |
| 638 | for(const path::value_type* it = x.c_str(); *it; ++it) |
| 639 | hash_combine(seed, *it == '/' ? L'\\' : *it); |
| 640 | return seed; |
| 641 | # else // NDNBOOST_POSIX_API |
| 642 | return hash_range(x.native().begin(), x.native().end()); |
| 643 | # endif |
| 644 | } |
| 645 | |
| 646 | inline void swap(path& lhs, path& rhs) { lhs.swap(rhs); } |
| 647 | |
| 648 | inline path operator/(const path& lhs, const path& rhs) { return path(lhs) /= rhs; } |
| 649 | |
| 650 | // inserters and extractors |
| 651 | // use ndnboost::io::quoted() to handle spaces in paths |
| 652 | // use '&' as escape character to ease use for Windows paths |
| 653 | |
| 654 | template <class Char, class Traits> |
| 655 | inline std::basic_ostream<Char, Traits>& |
| 656 | operator<<(std::basic_ostream<Char, Traits>& os, const path& p) |
| 657 | { |
| 658 | return os |
| 659 | << ndnboost::io::quoted(p.template string<std::basic_string<Char> >(), static_cast<Char>('&')); |
| 660 | } |
| 661 | |
| 662 | template <class Char, class Traits> |
| 663 | inline std::basic_istream<Char, Traits>& |
| 664 | operator>>(std::basic_istream<Char, Traits>& is, path& p) |
| 665 | { |
| 666 | std::basic_string<Char> str; |
| 667 | is >> ndnboost::io::quoted(str, static_cast<Char>('&')); |
| 668 | p = str; |
| 669 | return is; |
| 670 | } |
| 671 | |
| 672 | // name_checks |
| 673 | |
| 674 | // These functions are holdovers from version 1. It isn't clear they have much |
| 675 | // usefulness, or how to generalize them for later versions. |
| 676 | |
| 677 | NDNBOOST_FILESYSTEM_DECL bool portable_posix_name(const std::string & name); |
| 678 | NDNBOOST_FILESYSTEM_DECL bool windows_name(const std::string & name); |
| 679 | NDNBOOST_FILESYSTEM_DECL bool portable_name(const std::string & name); |
| 680 | NDNBOOST_FILESYSTEM_DECL bool portable_directory_name(const std::string & name); |
| 681 | NDNBOOST_FILESYSTEM_DECL bool portable_file_name(const std::string & name); |
| 682 | NDNBOOST_FILESYSTEM_DECL bool native(const std::string & name); |
| 683 | |
| 684 | //--------------------------------------------------------------------------------------// |
| 685 | // class path member template implementation // |
| 686 | //--------------------------------------------------------------------------------------// |
| 687 | |
| 688 | template <class InputIterator> |
| 689 | path& path::append(InputIterator begin, InputIterator end, const codecvt_type& cvt) |
| 690 | { |
| 691 | if (begin == end) |
| 692 | return *this; |
| 693 | string_type::size_type sep_pos(m_append_separator_if_needed()); |
| 694 | std::basic_string<typename std::iterator_traits<InputIterator>::value_type> |
| 695 | s(begin, end); |
| 696 | path_traits::convert(s.c_str(), s.c_str()+s.size(), m_pathname, cvt); |
| 697 | if (sep_pos) |
| 698 | m_erase_redundant_separator(sep_pos); |
| 699 | return *this; |
| 700 | } |
| 701 | |
| 702 | template <class Source> |
| 703 | path& path::append(Source const& source, const codecvt_type& cvt) |
| 704 | { |
| 705 | if (path_traits::empty(source)) |
| 706 | return *this; |
| 707 | string_type::size_type sep_pos(m_append_separator_if_needed()); |
| 708 | path_traits::dispatch(source, m_pathname, cvt); |
| 709 | if (sep_pos) |
| 710 | m_erase_redundant_separator(sep_pos); |
| 711 | return *this; |
| 712 | } |
| 713 | |
| 714 | //--------------------------------------------------------------------------------------// |
| 715 | // class path member template specializations // |
| 716 | //--------------------------------------------------------------------------------------// |
| 717 | |
| 718 | template <> inline |
| 719 | std::string path::string<std::string>() const |
| 720 | { return string(); } |
| 721 | |
| 722 | template <> inline |
| 723 | std::wstring path::string<std::wstring>() const |
| 724 | { return wstring(); } |
| 725 | |
| 726 | template <> inline |
| 727 | std::string path::string<std::string>(const codecvt_type& cvt) const |
| 728 | { return string(cvt); } |
| 729 | |
| 730 | template <> inline |
| 731 | std::wstring path::string<std::wstring>(const codecvt_type& cvt) const |
| 732 | { return wstring(cvt); } |
| 733 | |
| 734 | template <> inline |
| 735 | std::string path::generic_string<std::string>() const |
| 736 | { return generic_string(); } |
| 737 | |
| 738 | template <> inline |
| 739 | std::wstring path::generic_string<std::wstring>() const |
| 740 | { return generic_wstring(); } |
| 741 | |
| 742 | template <> inline |
| 743 | std::string path::generic_string<std::string>(const codecvt_type& cvt) const |
| 744 | { return generic_string(cvt); } |
| 745 | |
| 746 | template <> inline |
| 747 | std::wstring path::generic_string<std::wstring>(const codecvt_type& cvt) const |
| 748 | { return generic_wstring(cvt); } |
| 749 | |
| 750 | |
| 751 | } // namespace filesystem |
| 752 | } // namespace ndnboost |
| 753 | |
| 754 | //----------------------------------------------------------------------------// |
| 755 | |
| 756 | #include <ndnboost/config/abi_suffix.hpp> // pops abi_prefix.hpp pragmas |
| 757 | |
| 758 | #endif // NDNBOOST_FILESYSTEM_PATH_HPP |