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
45namespace boost
46{
47namespace 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
973namespace 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