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