1 // boost/filesystem/path.hpp -----------------------------------------------//
\r
3 // Copyright Beman Dawes 2002-2005
\r
4 // Copyright Vladimir Prus 2002
\r
6 // Distributed under the Boost Software License, Version 1.0. (See accompanying
\r
7 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
\r
9 // See library home page at http://www.boost.org/libs/filesystem
\r
11 // basic_path's stem(), extension(), and replace_extension() are based on
\r
12 // basename(), extension(), and change_extension() from the original
\r
13 // filesystem/convenience.hpp header by Vladimir Prus.
\r
15 //----------------------------------------------------------------------------//
\r
17 #ifndef BOOST_FILESYSTEM_PATH_HPP
\r
18 #define BOOST_FILESYSTEM_PATH_HPP
\r
20 #include <boost/filesystem/config.hpp>
\r
21 #include <boost/system/system_error.hpp>
\r
22 #include <boost/iterator/iterator_facade.hpp>
\r
23 #include <boost/throw_exception.hpp>
\r
24 #include <boost/shared_ptr.hpp>
\r
25 #include <boost/type_traits/is_same.hpp>
\r
26 #include <boost/static_assert.hpp>
\r
29 #include <algorithm> // for lexicographical_compare
\r
30 #include <iosfwd> // needed by basic_path inserter and extractor
\r
31 #include <stdexcept>
\r
34 # ifndef BOOST_FILESYSTEM_NARROW_ONLY
\r
38 #include <boost/config/abi_prefix.hpp> // must be the last #include
\r
40 //----------------------------------------------------------------------------//
\r
44 namespace BOOST_FILESYSTEM_NAMESPACE
\r
46 template<class String, class Traits> class basic_path;
\r
49 typedef basic_path< std::string, path_traits > path;
\r
53 typedef std::string internal_string_type;
\r
54 typedef std::string external_string_type;
\r
55 static external_string_type to_external( const path &,
\r
56 const internal_string_type & src ) { return src; }
\r
57 static internal_string_type to_internal(
\r
58 const external_string_type & src ) { return src; }
\r
61 # ifndef BOOST_FILESYSTEM_NARROW_ONLY
\r
63 struct BOOST_FILESYSTEM_DECL wpath_traits;
\r
65 typedef basic_path< std::wstring, wpath_traits > wpath;
\r
67 struct BOOST_FILESYSTEM_DECL wpath_traits
\r
69 typedef std::wstring internal_string_type;
\r
70 # ifdef BOOST_WINDOWS_API
\r
71 typedef std::wstring external_string_type;
\r
72 static external_string_type to_external( const wpath &,
\r
73 const internal_string_type & src ) { return src; }
\r
74 static internal_string_type to_internal(
\r
75 const external_string_type & src ) { return src; }
\r
77 typedef std::string external_string_type;
\r
78 static external_string_type to_external( const wpath & ph,
\r
79 const internal_string_type & src );
\r
80 static internal_string_type to_internal(
\r
81 const external_string_type & src );
\r
83 static void imbue( const std::locale & loc );
\r
84 static bool imbue( const std::locale & loc, const std::nothrow_t & );
\r
87 # endif // ifndef BOOST_FILESYSTEM_NARROW_ONLY
\r
89 // path traits ---------------------------------------------------------//
\r
91 template<class Path> struct is_basic_path
\r
92 { BOOST_STATIC_CONSTANT( bool, value = false ); };
\r
93 template<> struct is_basic_path<path>
\r
94 { BOOST_STATIC_CONSTANT( bool, value = true ); };
\r
95 # ifndef BOOST_FILESYSTEM_NARROW_ONLY
\r
96 template<> struct is_basic_path<wpath>
\r
97 { BOOST_STATIC_CONSTANT( bool, value = true ); };
\r
100 // These only have to be specialized if Path::string_type::value_type
\r
101 // is not convertible from char, although specializations may eliminate
\r
102 // compiler warnings. See ticket 2543.
\r
103 template<class Path> struct slash
\r
104 { BOOST_STATIC_CONSTANT( char, value = '/' ); };
\r
106 template<class Path> struct dot
\r
107 { BOOST_STATIC_CONSTANT( char, value = '.' ); };
\r
109 template<class Path> struct colon
\r
110 { BOOST_STATIC_CONSTANT( char, value = ':' ); };
\r
112 # ifndef BOOST_FILESYSTEM_NARROW_ONLY
\r
113 template<> struct slash<wpath>
\r
114 { BOOST_STATIC_CONSTANT( wchar_t, value = L'/' ); };
\r
115 template<> struct dot<wpath>
\r
116 { BOOST_STATIC_CONSTANT( wchar_t, value = L'.' ); };
\r
117 template<> struct colon<wpath>
\r
118 { BOOST_STATIC_CONSTANT( wchar_t, value = L':' ); };
\r
121 # ifdef BOOST_WINDOWS_PATH
\r
122 template<class Path> struct path_alt_separator
\r
123 { BOOST_STATIC_CONSTANT( char, value = '\\' ); };
\r
124 # ifndef BOOST_FILESYSTEM_NARROW_ONLY
\r
125 template<> struct path_alt_separator<wpath>
\r
126 { BOOST_STATIC_CONSTANT( wchar_t, value = L'\\' ); };
\r
130 // workaround for VC++ 7.0 and earlier issues with nested classes
\r
133 template<class Path>
\r
134 class iterator_helper
\r
137 typedef typename Path::iterator iterator;
\r
138 static void do_increment( iterator & ph );
\r
139 static void do_decrement( iterator & ph );
\r
143 // basic_path ----------------------------------------------------------//
\r
145 template<class String, class Traits>
\r
148 // invariant: m_path valid according to the portable generic path grammar
\r
150 // validate template arguments
\r
151 // TODO: get these working
\r
152 // BOOST_STATIC_ASSERT( ::boost::is_same<String,typename Traits::internal_string_type>::value );
\r
153 // BOOST_STATIC_ASSERT( ::boost::is_same<typename Traits::external_string_type,std::string>::value || ::boost::is_same<typename Traits::external_string_type,std::wstring>::value );
\r
156 // compiler generates copy constructor and copy assignment
\r
158 typedef basic_path<String, Traits> path_type;
\r
159 typedef String string_type;
\r
160 typedef typename String::value_type value_type;
\r
161 typedef Traits traits_type;
\r
162 typedef typename Traits::external_string_type external_string_type;
\r
164 // constructors/destructor
\r
166 basic_path( const string_type & s ) { operator/=( s ); }
\r
167 basic_path( const value_type * s ) { operator/=( s ); }
\r
168 # ifndef BOOST_NO_MEMBER_TEMPLATES
\r
169 template <class InputIterator>
\r
170 basic_path( InputIterator first, InputIterator last )
\r
171 { append( first, last ); }
\r
176 basic_path & operator=( const string_type & s )
\r
178 # if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, >= 310)
\r
181 m_path.erase( m_path.begin(), m_path.end() );
\r
186 basic_path & operator=( const value_type * s )
\r
188 # if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, >= 310)
\r
191 m_path.erase( m_path.begin(), m_path.end() );
\r
196 # ifndef BOOST_NO_MEMBER_TEMPLATES
\r
197 template <class InputIterator>
\r
198 basic_path & assign( InputIterator first, InputIterator last )
\r
199 { m_path.clear(); append( first, last ); return *this; }
\r
203 basic_path & operator/=( const basic_path & rhs ) { return operator /=( rhs.string().c_str() ); }
\r
204 basic_path & operator/=( const string_type & rhs ) { return operator /=( rhs.c_str() ); }
\r
205 basic_path & operator/=( const value_type * s );
\r
206 # ifndef BOOST_NO_MEMBER_TEMPLATES
\r
207 template <class InputIterator>
\r
208 basic_path & append( InputIterator first, InputIterator last );
\r
213 # if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, >= 310)
\r
216 m_path.erase( m_path.begin(), m_path.end() );
\r
220 void swap( basic_path & rhs )
\r
222 m_path.swap( rhs.m_path );
\r
223 # ifdef BOOST_CYGWIN_PATH
\r
224 std::swap( m_cygwin_root, rhs.m_cygwin_root );
\r
228 basic_path & remove_filename();
\r
229 basic_path & replace_extension( const string_type & new_extension = string_type() );
\r
231 # ifndef BOOST_FILESYSTEM_NO_DEPRECATED
\r
232 basic_path & remove_leaf() { return remove_filename(); }
\r
236 const string_type & string() const { return m_path; }
\r
237 const string_type file_string() const;
\r
238 const string_type directory_string() const { return file_string(); }
\r
240 const external_string_type external_file_string() const { return Traits::to_external( *this, file_string() ); }
\r
241 const external_string_type external_directory_string() const { return Traits::to_external( *this, directory_string() ); }
\r
243 basic_path root_path() const;
\r
244 string_type root_name() const;
\r
245 string_type root_directory() const;
\r
246 basic_path relative_path() const;
\r
247 basic_path parent_path() const;
\r
248 string_type filename() const;
\r
249 string_type stem() const;
\r
250 string_type extension() const;
\r
252 # ifndef BOOST_FILESYSTEM_NO_DEPRECATED
\r
253 string_type leaf() const { return filename(); }
\r
254 basic_path branch_path() const { return parent_path(); }
\r
255 bool has_leaf() const { return !m_path.empty(); }
\r
256 bool has_branch_path() const { return !parent_path().empty(); }
\r
259 bool empty() const { return m_path.empty(); } // name consistent with std containers
\r
260 bool is_complete() const;
\r
261 bool has_root_path() const;
\r
262 bool has_root_name() const;
\r
263 bool has_root_directory() const;
\r
264 bool has_relative_path() const { return !relative_path().empty(); }
\r
265 bool has_filename() const { return !m_path.empty(); }
\r
266 bool has_parent_path() const { return !parent_path().empty(); }
\r
269 class iterator : public boost::iterator_facade<
\r
272 boost::bidirectional_traversal_tag >
\r
275 friend class boost::iterator_core_access;
\r
276 friend class boost::BOOST_FILESYSTEM_NAMESPACE::basic_path<String, Traits>;
\r
278 const string_type & dereference() const
\r
280 bool equal( const iterator & rhs ) const
\r
281 { return m_path_ptr == rhs.m_path_ptr && m_pos == rhs.m_pos; }
\r
283 friend class boost::BOOST_FILESYSTEM_NAMESPACE::detail::iterator_helper<path_type>;
\r
287 boost::BOOST_FILESYSTEM_NAMESPACE::detail::iterator_helper<path_type>::do_increment(
\r
292 boost::BOOST_FILESYSTEM_NAMESPACE::detail::iterator_helper<path_type>::do_decrement(
\r
296 string_type m_name; // current element
\r
297 const basic_path * m_path_ptr; // path being iterated over
\r
298 typename string_type::size_type m_pos; // position of name in
\r
299 // path_ptr->string(). The
\r
300 // end() iterator is indicated by
\r
301 // pos == path_ptr->m_path.size()
\r
304 typedef iterator const_iterator;
\r
306 iterator begin() const;
\r
307 iterator end() const;
\r
310 // Note: This is an implementation for POSIX and Windows, where there
\r
311 // are only minor differences between generic and native path grammars.
\r
312 // Private members might be quite different in other implementations,
\r
313 // particularly where there were wide differences between portable and
\r
314 // native path formats, or between file_string() and
\r
315 // directory_string() formats, or simply that the implementation
\r
316 // was willing expend additional memory to achieve greater speed for
\r
317 // some operations at the expense of other operations.
\r
319 string_type m_path; // invariant: portable path grammar
\r
320 // on Windows, backslashes converted to slashes
\r
322 # ifdef BOOST_CYGWIN_PATH
\r
323 bool m_cygwin_root; // if present, m_path[0] was slash. note: initialization
\r
327 void m_append_separator_if_needed();
\r
328 void m_append( value_type value ); // converts Windows alt_separator
\r
330 // Was qualified; como433beta8 reports:
\r
331 // warning #427-D: qualified name is not allowed in member declaration
\r
332 friend class iterator;
\r
333 friend class boost::BOOST_FILESYSTEM_NAMESPACE::detail::iterator_helper<path_type>;
\r
335 // Deprecated features ease transition for existing code. Don't use these
\r
337 # ifndef BOOST_FILESYSTEM_NO_DEPRECATED
\r
339 typedef bool (*name_check)( const std::string & name );
\r
340 basic_path( const string_type & str, name_check ) { operator/=( str ); }
\r
341 basic_path( const typename string_type::value_type * s, name_check )
\r
342 { operator/=( s );}
\r
343 string_type native_file_string() const { return file_string(); }
\r
344 string_type native_directory_string() const { return directory_string(); }
\r
345 static bool default_name_check_writable() { return false; }
\r
346 static void default_name_check( name_check ) {}
\r
347 static name_check default_name_check() { return 0; }
\r
348 basic_path & canonize();
\r
349 basic_path & normalize();
\r
353 // basic_path non-member functions ---------------------------------------//
\r
355 template< class String, class Traits >
\r
356 inline void swap( basic_path<String, Traits> & lhs,
\r
357 basic_path<String, Traits> & rhs ) { lhs.swap( rhs ); }
\r
359 template< class String, class Traits >
\r
360 bool operator<( const basic_path<String, Traits> & lhs, const basic_path<String, Traits> & rhs )
\r
362 return std::lexicographical_compare(
\r
363 lhs.begin(), lhs.end(), rhs.begin(), rhs.end() );
\r
366 template< class String, class Traits >
\r
367 bool operator<( const typename basic_path<String, Traits>::string_type::value_type * lhs,
\r
368 const basic_path<String, Traits> & rhs )
\r
370 basic_path<String, Traits> tmp( lhs );
\r
371 return std::lexicographical_compare(
\r
372 tmp.begin(), tmp.end(), rhs.begin(), rhs.end() );
\r
375 template< class String, class Traits >
\r
376 bool operator<( const typename basic_path<String, Traits>::string_type & lhs,
\r
377 const basic_path<String, Traits> & rhs )
\r
379 basic_path<String, Traits> tmp( lhs );
\r
380 return std::lexicographical_compare(
\r
381 tmp.begin(), tmp.end(), rhs.begin(), rhs.end() );
\r
384 template< class String, class Traits >
\r
385 bool operator<( const basic_path<String, Traits> & lhs,
\r
386 const typename basic_path<String, Traits>::string_type::value_type * rhs )
\r
388 basic_path<String, Traits> tmp( rhs );
\r
389 return std::lexicographical_compare(
\r
390 lhs.begin(), lhs.end(), tmp.begin(), tmp.end() );
\r
393 template< class String, class Traits >
\r
394 bool operator<( const basic_path<String, Traits> & lhs,
\r
395 const typename basic_path<String, Traits>::string_type & rhs )
\r
397 basic_path<String, Traits> tmp( rhs );
\r
398 return std::lexicographical_compare(
\r
399 lhs.begin(), lhs.end(), tmp.begin(), tmp.end() );
\r
402 // operator == uses hand-written compare rather than !(lhs < rhs) && !(rhs < lhs)
\r
403 // because the result is the same yet the direct compare is much more efficient
\r
404 // than lexicographical_compare, which would also be called twice.
\r
406 template< class String, class Traits >
\r
407 inline bool operator==( const basic_path<String, Traits> & lhs,
\r
408 const typename basic_path<String, Traits>::string_type::value_type * rhs )
\r
411 boost::BOOST_FILESYSTEM_NAMESPACE::basic_path<String, Traits> path_type;
\r
412 const typename path_type::string_type::value_type * l (lhs.string().c_str());
\r
413 while ( (*l == *rhs
\r
414 # ifdef BOOST_WINDOWS_PATH
\r
415 || (*l == path_alt_separator<path_type>::value && *rhs == slash<path_type>::value)
\r
416 || (*l == slash<path_type>::value && *rhs == path_alt_separator<path_type>::value)
\r
418 ) && *l ) { ++l; ++rhs; }
\r
420 # ifdef BOOST_WINDOWS_PATH
\r
421 || (*l == path_alt_separator<path_type>::value && *rhs == slash<path_type>::value)
\r
422 || (*l == slash<path_type>::value && *rhs == path_alt_separator<path_type>::value)
\r
427 template< class String, class Traits >
\r
428 inline bool operator==( const basic_path<String, Traits> & lhs,
\r
429 const basic_path<String, Traits> & rhs )
\r
431 return lhs == rhs.string().c_str();
\r
434 template< class String, class Traits >
\r
435 inline bool operator==( const typename basic_path<String, Traits>::string_type::value_type * lhs,
\r
436 const basic_path<String, Traits> & rhs )
\r
441 template< class String, class Traits >
\r
442 inline bool operator==( const typename basic_path<String, Traits>::string_type & lhs,
\r
443 const basic_path<String, Traits> & rhs )
\r
445 return rhs == lhs.c_str();
\r
448 template< class String, class Traits >
\r
449 inline bool operator==( const basic_path<String, Traits> & lhs,
\r
450 const typename basic_path<String, Traits>::string_type & rhs )
\r
452 return lhs == rhs.c_str();
\r
455 template< class String, class Traits >
\r
456 inline bool operator!=( const basic_path<String, Traits> & lhs,
\r
457 const basic_path<String, Traits> & rhs )
\r
458 { return !(lhs == rhs); }
\r
460 template< class String, class Traits >
\r
461 inline bool operator!=( const typename basic_path<String,
\r
462 Traits>::string_type::value_type * lhs,
\r
463 const basic_path<String, Traits> & rhs )
\r
464 { return !(lhs == rhs); }
\r
466 template< class String, class Traits >
\r
467 inline bool operator!=( const typename basic_path<String, Traits>::string_type & lhs,
\r
468 const basic_path<String, Traits> & rhs )
\r
469 { return !(lhs == rhs); }
\r
471 template< class String, class Traits >
\r
472 inline bool operator!=( const basic_path<String, Traits> & lhs,
\r
473 const typename basic_path<String, Traits>::string_type::value_type * rhs )
\r
474 { return !(lhs == rhs); }
\r
476 template< class String, class Traits >
\r
477 inline bool operator!=( const basic_path<String, Traits> & lhs,
\r
478 const typename basic_path<String, Traits>::string_type & rhs )
\r
479 { return !(lhs == rhs); }
\r
481 template< class String, class Traits >
\r
482 inline bool operator>( const basic_path<String, Traits> & lhs, const basic_path<String, Traits> & rhs ) { return rhs < lhs; }
\r
484 template< class String, class Traits >
\r
485 inline bool operator>( const typename basic_path<String, Traits>::string_type::value_type * lhs,
\r
486 const basic_path<String, Traits> & rhs ) { return rhs < basic_path<String, Traits>(lhs); }
\r
488 template< class String, class Traits >
\r
489 inline bool operator>( const typename basic_path<String, Traits>::string_type & lhs,
\r
490 const basic_path<String, Traits> & rhs ) { return rhs < basic_path<String, Traits>(lhs); }
\r
492 template< class String, class Traits >
\r
493 inline bool operator>( const basic_path<String, Traits> & lhs,
\r
494 const typename basic_path<String, Traits>::string_type::value_type * rhs )
\r
495 { return basic_path<String, Traits>(rhs) < lhs; }
\r
497 template< class String, class Traits >
\r
498 inline bool operator>( const basic_path<String, Traits> & lhs,
\r
499 const typename basic_path<String, Traits>::string_type & rhs )
\r
500 { return basic_path<String, Traits>(rhs) < lhs; }
\r
502 template< class String, class Traits >
\r
503 inline bool operator<=( const basic_path<String, Traits> & lhs, const basic_path<String, Traits> & rhs ) { return !(rhs < lhs); }
\r
505 template< class String, class Traits >
\r
506 inline bool operator<=( const typename basic_path<String, Traits>::string_type::value_type * lhs,
\r
507 const basic_path<String, Traits> & rhs ) { return !(rhs < basic_path<String, Traits>(lhs)); }
\r
509 template< class String, class Traits >
\r
510 inline bool operator<=( const typename basic_path<String, Traits>::string_type & lhs,
\r
511 const basic_path<String, Traits> & rhs ) { return !(rhs < basic_path<String, Traits>(lhs)); }
\r
513 template< class String, class Traits >
\r
514 inline bool operator<=( const basic_path<String, Traits> & lhs,
\r
515 const typename basic_path<String, Traits>::string_type::value_type * rhs )
\r
516 { return !(basic_path<String, Traits>(rhs) < lhs); }
\r
518 template< class String, class Traits >
\r
519 inline bool operator<=( const basic_path<String, Traits> & lhs,
\r
520 const typename basic_path<String, Traits>::string_type & rhs )
\r
521 { return !(basic_path<String, Traits>(rhs) < lhs); }
\r
523 template< class String, class Traits >
\r
524 inline bool operator>=( const basic_path<String, Traits> & lhs, const basic_path<String, Traits> & rhs ) { return !(lhs < rhs); }
\r
526 template< class String, class Traits >
\r
527 inline bool operator>=( const typename basic_path<String, Traits>::string_type::value_type * lhs,
\r
528 const basic_path<String, Traits> & rhs ) { return !(lhs < basic_path<String, Traits>(rhs)); }
\r
530 template< class String, class Traits >
\r
531 inline bool operator>=( const typename basic_path<String, Traits>::string_type & lhs,
\r
532 const basic_path<String, Traits> & rhs ) { return !(lhs < basic_path<String, Traits>(rhs)); }
\r
534 template< class String, class Traits >
\r
535 inline bool operator>=( const basic_path<String, Traits> & lhs,
\r
536 const typename basic_path<String, Traits>::string_type::value_type * rhs )
\r
537 { return !(basic_path<String, Traits>(lhs) < rhs); }
\r
539 template< class String, class Traits >
\r
540 inline bool operator>=( const basic_path<String, Traits> & lhs,
\r
541 const typename basic_path<String, Traits>::string_type & rhs )
\r
542 { return !(basic_path<String, Traits>(lhs) < rhs); }
\r
546 template< class String, class Traits >
\r
547 inline basic_path<String, Traits> operator/(
\r
548 const basic_path<String, Traits> & lhs,
\r
549 const basic_path<String, Traits> & rhs )
\r
550 { return basic_path<String, Traits>( lhs ) /= rhs; }
\r
552 template< class String, class Traits >
\r
553 inline basic_path<String, Traits> operator/(
\r
554 const basic_path<String, Traits> & lhs,
\r
555 const typename String::value_type * rhs )
\r
556 { return basic_path<String, Traits>( lhs ) /=
\r
557 basic_path<String, Traits>( rhs ); }
\r
559 template< class String, class Traits >
\r
560 inline basic_path<String, Traits> operator/(
\r
561 const basic_path<String, Traits> & lhs, const String & rhs )
\r
562 { return basic_path<String, Traits>( lhs ) /=
\r
563 basic_path<String, Traits>( rhs ); }
\r
565 template< class String, class Traits >
\r
566 inline basic_path<String, Traits> operator/(
\r
567 const typename String::value_type * lhs,
\r
568 const basic_path<String, Traits> & rhs )
\r
569 { return basic_path<String, Traits>( lhs ) /= rhs; }
\r
571 template< class String, class Traits >
\r
572 inline basic_path<String, Traits> operator/(
\r
573 const String & lhs, const basic_path<String, Traits> & rhs )
\r
574 { return basic_path<String, Traits>( lhs ) /= rhs; }
\r
576 // inserters and extractors --------------------------------------------//
\r
578 // bypass VC++ 7.0 and earlier, and broken Borland compilers
\r
579 # if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) && !BOOST_WORKAROUND(__BORLANDC__, < 0x610)
\r
580 template< class Path >
\r
581 std::basic_ostream< typename Path::string_type::value_type,
\r
582 typename Path::string_type::traits_type > &
\r
584 ( std::basic_ostream< typename Path::string_type::value_type,
\r
585 typename Path::string_type::traits_type >& os, const Path & ph )
\r
591 template< class Path >
\r
592 std::basic_istream< typename Path::string_type::value_type,
\r
593 typename Path::string_type::traits_type > &
\r
595 ( std::basic_istream< typename Path::string_type::value_type,
\r
596 typename Path::string_type::traits_type >& is, Path & ph )
\r
598 typename Path::string_type str;
\r
603 # elif BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
\r
604 template< class String, class Traits >
\r
605 std::basic_ostream< BOOST_DEDUCED_TYPENAME String::value_type,
\r
606 BOOST_DEDUCED_TYPENAME String::traits_type > &
\r
608 ( std::basic_ostream< BOOST_DEDUCED_TYPENAME String::value_type,
\r
609 BOOST_DEDUCED_TYPENAME String::traits_type >& os,
\r
610 const basic_path< String, Traits > & ph )
\r
616 template< class String, class Traits >
\r
617 std::basic_istream< BOOST_DEDUCED_TYPENAME String::value_type,
\r
618 BOOST_DEDUCED_TYPENAME String::traits_type > &
\r
620 ( std::basic_istream< BOOST_DEDUCED_TYPENAME String::value_type,
\r
621 BOOST_DEDUCED_TYPENAME String::traits_type> & is,
\r
622 basic_path< String, Traits > & ph )
\r
631 // basic_filesystem_error helpers --------------------------------------//
\r
633 // Originally choice of implementation was done via specialization of
\r
634 // basic_filesystem_error::what(). Several compilers (GCC, aCC, etc.)
\r
635 // couldn't handle that, so the choice is now accomplished by overloading.
\r
639 // BOOST_FILESYSTEM_DECL version works for VC++ but not GCC. Go figure!
\r
641 const char * what( const char * sys_err_what,
\r
642 const path & path1_arg, const path & path2_arg, std::string & target )
\r
646 if ( target.empty() )
\r
648 target = sys_err_what;
\r
649 if ( !path1_arg.empty() )
\r
652 target += path1_arg.file_string();
\r
655 if ( !path2_arg.empty() )
\r
658 target += path2_arg.file_string();
\r
662 return target.c_str();
\r
666 return sys_err_what;
\r
670 template<class Path>
\r
671 const char * what( const char * sys_err_what,
\r
672 const Path & /*path1_arg*/, const Path & /*path2_arg*/, std::string & /*target*/ )
\r
674 return sys_err_what;
\r
678 // basic_filesystem_error ----------------------------------------------//
\r
680 template<class Path>
\r
681 class basic_filesystem_error : public system::system_error
\r
683 // see http://www.boost.org/more/error_handling.html for design rationale
\r
685 // compiler generates copy constructor and copy assignment
\r
687 typedef Path path_type;
\r
689 basic_filesystem_error( const std::string & what_arg,
\r
690 system::error_code ec );
\r
692 basic_filesystem_error( const std::string & what_arg,
\r
693 const path_type & path1_arg, system::error_code ec );
\r
695 basic_filesystem_error( const std::string & what_arg, const path_type & path1_arg,
\r
696 const path_type & path2_arg, system::error_code ec );
\r
698 ~basic_filesystem_error() throw() {}
\r
700 const path_type & path1() const
\r
702 static const path_type empty_path;
\r
703 return m_imp_ptr.get() ? m_imp_ptr->m_path1 : empty_path ;
\r
705 const path_type & path2() const
\r
707 static const path_type empty_path;
\r
708 return m_imp_ptr.get() ? m_imp_ptr->m_path2 : empty_path ;
\r
711 const char * what() const throw()
\r
713 if ( !m_imp_ptr.get() )
\r
714 return system::system_error::what();
\r
715 return detail::what( system::system_error::what(), m_imp_ptr->m_path1,
\r
716 m_imp_ptr->m_path2, m_imp_ptr->m_what );
\r
722 path_type m_path1; // may be empty()
\r
723 path_type m_path2; // may be empty()
\r
724 std::string m_what; // not built until needed
\r
726 boost::shared_ptr<m_imp> m_imp_ptr;
\r
729 typedef basic_filesystem_error<path> filesystem_error;
\r
731 # ifndef BOOST_FILESYSTEM_NARROW_ONLY
\r
732 typedef basic_filesystem_error<wpath> wfilesystem_error;
\r
735 // path::name_checks -----------------------------------------------------//
\r
737 BOOST_FILESYSTEM_DECL bool portable_posix_name( const std::string & name );
\r
738 BOOST_FILESYSTEM_DECL bool windows_name( const std::string & name );
\r
739 BOOST_FILESYSTEM_DECL bool portable_name( const std::string & name );
\r
740 BOOST_FILESYSTEM_DECL bool portable_directory_name( const std::string & name );
\r
741 BOOST_FILESYSTEM_DECL bool portable_file_name( const std::string & name );
\r
742 BOOST_FILESYSTEM_DECL bool native( const std::string & name );
\r
743 inline bool no_check( const std::string & )
\r
746 // implementation -----------------------------------------------------------//
\r
751 // is_separator helper ------------------------------------------------//
\r
753 template<class Path>
\r
754 inline bool is_separator( typename Path::string_type::value_type c )
\r
756 return c == slash<Path>::value
\r
757 # ifdef BOOST_WINDOWS_PATH
\r
758 || c == path_alt_separator<Path>::value
\r
763 // filename_pos helper ----------------------------------------------------//
\r
765 template<class String, class Traits>
\r
766 typename String::size_type filename_pos(
\r
767 const String & str, // precondition: portable generic path grammar
\r
768 typename String::size_type end_pos ) // end_pos is past-the-end position
\r
769 // return 0 if str itself is filename (or empty)
\r
772 boost::BOOST_FILESYSTEM_NAMESPACE::basic_path<String, Traits> path_type;
\r
776 && str[0] == slash<path_type>::value
\r
777 && str[1] == slash<path_type>::value ) return 0;
\r
779 // case: ends in "/"
\r
780 if ( end_pos && str[end_pos-1] == slash<path_type>::value )
\r
783 // set pos to start of last element
\r
784 typename String::size_type pos(
\r
785 str.find_last_of( slash<path_type>::value, end_pos-1 ) );
\r
786 # ifdef BOOST_WINDOWS_PATH
\r
787 if ( pos == String::npos )
\r
788 pos = str.find_last_of( path_alt_separator<path_type>::value, end_pos-1 );
\r
789 if ( pos == String::npos )
\r
790 pos = str.find_last_of( colon<path_type>::value, end_pos-2 );
\r
793 return ( pos == String::npos // path itself must be a filename (or empty)
\r
794 || (pos == 1 && str[0] == slash<path_type>::value) ) // or net
\r
795 ? 0 // so filename is entire string
\r
796 : pos + 1; // or starts after delimiter
\r
799 // first_element helper -----------------------------------------------//
\r
800 // sets pos and len of first element, excluding extra separators
\r
801 // if src.empty(), sets pos,len, to 0,0.
\r
803 template<class String, class Traits>
\r
804 void first_element(
\r
805 const String & src, // precondition: portable generic path grammar
\r
806 typename String::size_type & element_pos,
\r
807 typename String::size_type & element_size,
\r
808 # if !BOOST_WORKAROUND( BOOST_MSVC, <= 1310 ) // VC++ 7.1
\r
809 typename String::size_type size = String::npos
\r
811 typename String::size_type size = -1
\r
815 if ( size == String::npos ) size = src.size();
\r
818 if ( src.empty() ) return;
\r
820 typedef typename boost::BOOST_FILESYSTEM_NAMESPACE::basic_path<String, Traits> path_type;
\r
822 typename String::size_type cur(0);
\r
824 // deal with // [network]
\r
825 if ( size >= 2 && src[0] == slash<path_type>::value
\r
826 && src[1] == slash<path_type>::value
\r
828 || src[2] != slash<path_type>::value) )
\r
834 // leading (not non-network) separator
\r
835 else if ( src[0] == slash<path_type>::value )
\r
838 // bypass extra leading separators
\r
839 while ( cur+1 < size
\r
840 && src[cur+1] == slash<path_type>::value )
\r
848 // at this point, we have either a plain name, a network name,
\r
849 // or (on Windows only) a device name
\r
853 # ifdef BOOST_WINDOWS_PATH
\r
854 && src[cur] != colon<path_type>::value
\r
856 && src[cur] != slash<path_type>::value )
\r
862 # ifdef BOOST_WINDOWS_PATH
\r
863 if ( cur == size ) return;
\r
864 // include device delimiter
\r
865 if ( src[cur] == colon<path_type>::value )
\r
866 { ++element_size; }
\r
872 // root_directory_start helper ----------------------------------------//
\r
874 template<class String, class Traits>
\r
875 typename String::size_type root_directory_start(
\r
876 const String & s, // precondition: portable generic path grammar
\r
877 typename String::size_type size )
\r
878 // return npos if no root_directory found
\r
880 typedef typename boost::BOOST_FILESYSTEM_NAMESPACE::basic_path<String, Traits> path_type;
\r
882 # ifdef BOOST_WINDOWS_PATH
\r
885 && s[1] == colon<path_type>::value
\r
886 && s[2] == slash<path_type>::value ) return 2;
\r
891 && s[0] == slash<path_type>::value
\r
892 && s[1] == slash<path_type>::value ) return String::npos;
\r
894 // case "//net {/}"
\r
896 && s[0] == slash<path_type>::value
\r
897 && s[1] == slash<path_type>::value
\r
898 && s[2] != slash<path_type>::value )
\r
900 typename String::size_type pos(
\r
901 s.find( slash<path_type>::value, 2 ) );
\r
902 return pos < size ? pos : String::npos;
\r
906 if ( size > 0 && s[0] == slash<path_type>::value ) return 0;
\r
908 return String::npos;
\r
911 // is_non_root_slash helper -------------------------------------------//
\r
913 template<class String, class Traits>
\r
914 bool is_non_root_slash( const String & str,
\r
915 typename String::size_type pos ) // pos is position of the slash
\r
918 boost::BOOST_FILESYSTEM_NAMESPACE::basic_path<String, Traits>
\r
921 assert( !str.empty() && str[pos] == slash<path_type>::value
\r
922 && "precondition violation" );
\r
924 // subsequent logic expects pos to be for leftmost slash of a set
\r
925 while ( pos > 0 && str[pos-1] == slash<path_type>::value )
\r
929 && (pos <= 2 || str[1] != slash<path_type>::value
\r
930 || str.find( slash<path_type>::value, 2 ) != pos)
\r
931 # ifdef BOOST_WINDOWS_PATH
\r
932 && (pos !=2 || str[1] != colon<path_type>::value)
\r
936 } // namespace detail
\r
938 // decomposition functions ----------------------------------------------//
\r
940 template<class String, class Traits>
\r
941 String basic_path<String, Traits>::filename() const
\r
943 typename String::size_type end_pos(
\r
944 detail::filename_pos<String, Traits>( m_path, m_path.size() ) );
\r
945 return (m_path.size()
\r
947 && m_path[end_pos] == slash<path_type>::value
\r
948 && detail::is_non_root_slash< String, Traits >(m_path, end_pos))
\r
949 ? String( 1, dot<path_type>::value )
\r
950 : m_path.substr( end_pos );
\r
953 template<class String, class Traits>
\r
954 String basic_path<String, Traits>::stem() const
\r
956 string_type name = filename();
\r
957 typename string_type::size_type n = name.rfind(dot<path_type>::value);
\r
958 return name.substr(0, n);
\r
961 template<class String, class Traits>
\r
962 String basic_path<String, Traits>::extension() const
\r
964 string_type name = filename();
\r
965 typename string_type::size_type n = name.rfind(dot<path_type>::value);
\r
966 if (n != string_type::npos)
\r
967 return name.substr(n);
\r
969 return string_type();
\r
972 template<class String, class Traits>
\r
973 basic_path<String, Traits> basic_path<String, Traits>::parent_path() const
\r
975 typename String::size_type end_pos(
\r
976 detail::filename_pos<String, Traits>( m_path, m_path.size() ) );
\r
978 bool filename_was_separator( m_path.size()
\r
979 && m_path[end_pos] == slash<path_type>::value );
\r
981 // skip separators unless root directory
\r
982 typename string_type::size_type root_dir_pos( detail::root_directory_start
\r
983 <string_type, traits_type>( m_path, end_pos ) );
\r
986 && (end_pos-1) != root_dir_pos
\r
987 && m_path[end_pos-1] == slash<path_type>::value
\r
991 return (end_pos == 1 && root_dir_pos == 0 && filename_was_separator)
\r
993 : path_type( m_path.substr( 0, end_pos ) );
\r
996 template<class String, class Traits>
\r
997 basic_path<String, Traits> basic_path<String, Traits>::relative_path() const
\r
999 iterator itr( begin() );
\r
1000 for ( ; itr.m_pos != m_path.size()
\r
1001 && (itr.m_name[0] == slash<path_type>::value
\r
1002 # ifdef BOOST_WINDOWS_PATH
\r
1003 || itr.m_name[itr.m_name.size()-1]
\r
1004 == colon<path_type>::value
\r
1008 return basic_path<String, Traits>( m_path.substr( itr.m_pos ) );
\r
1011 template<class String, class Traits>
\r
1012 String basic_path<String, Traits>::root_name() const
\r
1014 iterator itr( begin() );
\r
1016 return ( itr.m_pos != m_path.size()
\r
1018 ( itr.m_name.size() > 1
\r
1019 && itr.m_name[0] == slash<path_type>::value
\r
1020 && itr.m_name[1] == slash<path_type>::value
\r
1022 # ifdef BOOST_WINDOWS_PATH
\r
1023 || itr.m_name[itr.m_name.size()-1]
\r
1024 == colon<path_type>::value
\r
1031 template<class String, class Traits>
\r
1032 String basic_path<String, Traits>::root_directory() const
\r
1034 typename string_type::size_type start(
\r
1035 detail::root_directory_start<String, Traits>( m_path, m_path.size() ) );
\r
1037 return start == string_type::npos
\r
1039 : m_path.substr( start, 1 );
\r
1042 template<class String, class Traits>
\r
1043 basic_path<String, Traits> basic_path<String, Traits>::root_path() const
\r
1045 // even on POSIX, root_name() is non-empty() on network paths
\r
1046 return basic_path<String, Traits>( root_name() ) /= root_directory();
\r
1049 // path query functions -------------------------------------------------//
\r
1051 template<class String, class Traits>
\r
1052 inline bool basic_path<String, Traits>::is_complete() const
\r
1054 # ifdef BOOST_WINDOWS_PATH
\r
1055 return has_root_name() && has_root_directory();
\r
1057 return has_root_directory();
\r
1061 template<class String, class Traits>
\r
1062 inline bool basic_path<String, Traits>::has_root_path() const
\r
1064 return !root_path().empty();
\r
1067 template<class String, class Traits>
\r
1068 inline bool basic_path<String, Traits>::has_root_name() const
\r
1070 return !root_name().empty();
\r
1073 template<class String, class Traits>
\r
1074 inline bool basic_path<String, Traits>::has_root_directory() const
\r
1076 return !root_directory().empty();
\r
1079 // append ---------------------------------------------------------------//
\r
1081 template<class String, class Traits>
\r
1082 void basic_path<String, Traits>::m_append_separator_if_needed()
\r
1083 // requires: !empty()
\r
1086 # ifdef BOOST_WINDOWS_PATH
\r
1087 *(m_path.end()-1) != colon<path_type>::value &&
\r
1089 *(m_path.end()-1) != slash<path_type>::value )
\r
1091 m_path += slash<path_type>::value;
\r
1095 template<class String, class Traits>
\r
1096 void basic_path<String, Traits>::m_append( value_type value )
\r
1098 # ifdef BOOST_CYGWIN_PATH
\r
1099 if ( m_path.empty() ) m_cygwin_root = (value == slash<path_type>::value);
\r
1102 # ifdef BOOST_WINDOWS_PATH
\r
1103 // for BOOST_WINDOWS_PATH, convert alt_separator ('\') to separator ('/')
\r
1104 m_path += ( value == path_alt_separator<path_type>::value
\r
1105 ? slash<path_type>::value
\r
1112 // except that it wouldn't work for BOOST_NO_MEMBER_TEMPLATES compilers,
\r
1113 // the append() member template could replace this code.
\r
1114 template<class String, class Traits>
\r
1115 basic_path<String, Traits> & basic_path<String, Traits>::operator /=
\r
1116 ( const value_type * next_p )
\r
1118 // ignore escape sequence on POSIX or Windows
\r
1119 if ( *next_p == slash<path_type>::value
\r
1120 && *(next_p+1) == slash<path_type>::value
\r
1121 && *(next_p+2) == colon<path_type>::value ) next_p += 3;
\r
1123 // append slash<path_type>::value if needed
\r
1124 if ( !empty() && *next_p != 0
\r
1125 && !detail::is_separator<path_type>( *next_p ) )
\r
1126 { m_append_separator_if_needed(); }
\r
1128 for ( ; *next_p != 0; ++next_p ) m_append( *next_p );
\r
1132 # ifndef BOOST_NO_MEMBER_TEMPLATES
\r
1133 template<class String, class Traits> template <class InputIterator>
\r
1134 basic_path<String, Traits> & basic_path<String, Traits>::append(
\r
1135 InputIterator first, InputIterator last )
\r
1137 // append slash<path_type>::value if needed
\r
1138 if ( !empty() && first != last
\r
1139 && !detail::is_separator<path_type>( *first ) )
\r
1140 { m_append_separator_if_needed(); }
\r
1142 // song-and-dance to avoid violating InputIterator requirements
\r
1143 // (which prohibit lookahead) in detecting a possible escape sequence
\r
1144 // (escape sequences are simply ignored on POSIX and Windows)
\r
1145 bool was_escape_sequence(true);
\r
1146 std::size_t append_count(0);
\r
1147 typename String::size_type initial_pos( m_path.size() );
\r
1149 for ( ; first != last && *first; ++first )
\r
1151 if ( append_count == 0 && *first != slash<path_type>::value )
\r
1152 was_escape_sequence = false;
\r
1153 if ( append_count == 1 && *first != slash<path_type>::value )
\r
1154 was_escape_sequence = false;
\r
1155 if ( append_count == 2 && *first != colon<path_type>::value )
\r
1156 was_escape_sequence = false;
\r
1157 m_append( *first );
\r
1161 // erase escape sequence if any
\r
1162 if ( was_escape_sequence && append_count >= 3 )
\r
1163 m_path.erase( initial_pos, 3 );
\r
1169 # ifndef BOOST_FILESYSTEM_NO_DEPRECATED
\r
1171 // canonize ------------------------------------------------------------//
\r
1173 template<class String, class Traits>
\r
1174 basic_path<String, Traits> & basic_path<String, Traits>::canonize()
\r
1176 static const typename string_type::value_type dot_str[]
\r
1177 = { dot<path_type>::value, 0 };
\r
1179 if ( m_path.empty() ) return *this;
\r
1183 for ( iterator itr( begin() ); itr != end(); ++itr )
\r
1188 if ( temp.empty() ) temp /= dot_str;
\r
1189 m_path = temp.m_path;
\r
1193 // normalize ------------------------------------------------------------//
\r
1195 template<class String, class Traits>
\r
1196 basic_path<String, Traits> & basic_path<String, Traits>::normalize()
\r
1198 static const typename string_type::value_type dot_str[]
\r
1199 = { dot<path_type>::value, 0 };
\r
1201 if ( m_path.empty() ) return *this;
\r
1204 iterator start( begin() );
\r
1205 iterator last( end() );
\r
1206 iterator stop( last-- );
\r
1207 for ( iterator itr( start ); itr != stop; ++itr )
\r
1209 // ignore "." except at start and last
\r
1210 if ( itr->size() == 1
\r
1211 && (*itr)[0] == dot<path_type>::value
\r
1213 && itr != last ) continue;
\r
1215 // ignore a name and following ".."
\r
1216 if ( !temp.empty()
\r
1217 && itr->size() == 2
\r
1218 && (*itr)[0] == dot<path_type>::value
\r
1219 && (*itr)[1] == dot<path_type>::value ) // dot dot
\r
1221 string_type lf( temp.filename() );
\r
1222 if ( lf.size() > 0
\r
1223 && (lf.size() != 1
\r
1224 || (lf[0] != dot<path_type>::value
\r
1225 && lf[0] != slash<path_type>::value))
\r
1226 && (lf.size() != 2
\r
1227 || (lf[0] != dot<path_type>::value
\r
1228 && lf[1] != dot<path_type>::value
\r
1229 # ifdef BOOST_WINDOWS_PATH
\r
1230 && lf[1] != colon<path_type>::value
\r
1236 temp.remove_filename();
\r
1237 // if not root directory, must also remove "/" if any
\r
1238 if ( temp.m_path.size() > 0
\r
1239 && temp.m_path[temp.m_path.size()-1]
\r
1240 == slash<path_type>::value )
\r
1242 typename string_type::size_type rds(
\r
1243 detail::root_directory_start<String,Traits>( temp.m_path,
\r
1244 temp.m_path.size() ) );
\r
1245 if ( rds == string_type::npos
\r
1246 || rds != temp.m_path.size()-1 )
\r
1247 { temp.m_path.erase( temp.m_path.size()-1 ); }
\r
1250 iterator next( itr );
\r
1251 if ( temp.empty() && ++next != stop
\r
1252 && next == last && *last == dot_str ) temp /= dot_str;
\r
1260 if ( temp.empty() ) temp /= dot_str;
\r
1261 m_path = temp.m_path;
\r
1267 // modifiers ------------------------------------------------------------//
\r
1269 template<class String, class Traits>
\r
1270 basic_path<String, Traits> & basic_path<String, Traits>::remove_filename()
\r
1273 detail::filename_pos<String, Traits>( m_path, m_path.size() ) );
\r
1277 template<class String, class Traits>
\r
1278 basic_path<String, Traits> &
\r
1279 basic_path<String, Traits>::replace_extension( const string_type & new_ext )
\r
1281 // erase existing extension if any
\r
1282 string_type old_ext = extension();
\r
1283 if ( !old_ext.empty() )
\r
1284 m_path.erase( m_path.size() - old_ext.size() );
\r
1286 if ( !new_ext.empty() && new_ext[0] != dot<path_type>::value )
\r
1287 m_path += dot<path_type>::value;
\r
1289 m_path += new_ext;
\r
1295 // path conversion functions --------------------------------------------//
\r
1297 template<class String, class Traits>
\r
1299 basic_path<String, Traits>::file_string() const
\r
1301 # ifdef BOOST_WINDOWS_PATH
\r
1302 // for Windows, use the alternate separator, and bypass extra
\r
1303 // root separators
\r
1305 typename string_type::size_type root_dir_start(
\r
1306 detail::root_directory_start<String, Traits>( m_path, m_path.size() ) );
\r
1307 bool in_root( root_dir_start != string_type::npos );
\r
1309 for ( typename string_type::size_type pos( 0 );
\r
1310 pos != m_path.size(); ++pos )
\r
1312 // special case // [net]
\r
1313 if ( pos == 0 && m_path.size() > 1
\r
1314 && m_path[0] == slash<path_type>::value
\r
1315 && m_path[1] == slash<path_type>::value
\r
1316 && ( m_path.size() == 2
\r
1317 || !detail::is_separator<path_type>( m_path[2] )
\r
1321 s += path_alt_separator<path_type>::value;
\r
1322 s += path_alt_separator<path_type>::value;
\r
1326 // bypass extra root separators
\r
1330 && s[s.size()-1] == path_alt_separator<path_type>::value
\r
1331 && m_path[pos] == slash<path_type>::value
\r
1335 if ( m_path[pos] == slash<path_type>::value )
\r
1336 s += path_alt_separator<path_type>::value;
\r
1340 if ( pos > root_dir_start
\r
1341 && m_path[pos] == slash<path_type>::value )
\r
1342 { in_root = false; }
\r
1344 # ifdef BOOST_CYGWIN_PATH
\r
1345 if ( m_cygwin_root ) s[0] = slash<path_type>::value;
\r
1353 // iterator functions ---------------------------------------------------//
\r
1355 template<class String, class Traits>
\r
1356 typename basic_path<String, Traits>::iterator basic_path<String, Traits>::begin() const
\r
1359 itr.m_path_ptr = this;
\r
1360 typename string_type::size_type element_size;
\r
1361 detail::first_element<String, Traits>( m_path, itr.m_pos, element_size );
\r
1362 itr.m_name = m_path.substr( itr.m_pos, element_size );
\r
1366 template<class String, class Traits>
\r
1367 typename basic_path<String, Traits>::iterator basic_path<String, Traits>::end() const
\r
1370 itr.m_path_ptr = this;
\r
1371 itr.m_pos = m_path.size();
\r
1377 // do_increment ------------------------------------------------------//
\r
1379 template<class Path>
\r
1380 void iterator_helper<Path>::do_increment( iterator & itr )
\r
1382 typedef typename Path::string_type string_type;
\r
1383 typedef typename Path::traits_type traits_type;
\r
1385 assert( itr.m_pos < itr.m_path_ptr->m_path.size() && "basic_path::iterator increment past end()" );
\r
1387 bool was_net( itr.m_name.size() > 2
\r
1388 && itr.m_name[0] == slash<Path>::value
\r
1389 && itr.m_name[1] == slash<Path>::value
\r
1390 && itr.m_name[2] != slash<Path>::value );
\r
1392 // increment to position past current element
\r
1393 itr.m_pos += itr.m_name.size();
\r
1395 // if end reached, create end iterator
\r
1396 if ( itr.m_pos == itr.m_path_ptr->m_path.size() )
\r
1398 itr.m_name.erase( itr.m_name.begin(), itr.m_name.end() ); // VC++ 6.0 lib didn't supply clear()
\r
1402 // process separator (Windows drive spec is only case not a separator)
\r
1403 if ( itr.m_path_ptr->m_path[itr.m_pos] == slash<Path>::value )
\r
1405 // detect root directory
\r
1407 # ifdef BOOST_WINDOWS_PATH
\r
1409 || itr.m_name[itr.m_name.size()-1] == colon<Path>::value
\r
1413 itr.m_name = slash<Path>::value;
\r
1417 // bypass separators
\r
1418 while ( itr.m_pos != itr.m_path_ptr->m_path.size()
\r
1419 && itr.m_path_ptr->m_path[itr.m_pos] == slash<Path>::value )
\r
1422 // detect trailing separator, and treat it as ".", per POSIX spec
\r
1423 if ( itr.m_pos == itr.m_path_ptr->m_path.size()
\r
1424 && detail::is_non_root_slash< string_type, traits_type >(
\r
1425 itr.m_path_ptr->m_path, itr.m_pos-1 ) )
\r
1428 itr.m_name = dot<Path>::value;
\r
1433 // get next element
\r
1434 typename string_type::size_type end_pos(
\r
1435 itr.m_path_ptr->m_path.find( slash<Path>::value, itr.m_pos ) );
\r
1436 itr.m_name = itr.m_path_ptr->m_path.substr( itr.m_pos, end_pos - itr.m_pos );
\r
1439 // do_decrement ------------------------------------------------------//
\r
1441 template<class Path>
\r
1442 void iterator_helper<Path>::do_decrement( iterator & itr )
\r
1444 assert( itr.m_pos && "basic_path::iterator decrement past begin()" );
\r
1446 typedef typename Path::string_type string_type;
\r
1447 typedef typename Path::traits_type traits_type;
\r
1449 typename string_type::size_type end_pos( itr.m_pos );
\r
1451 typename string_type::size_type root_dir_pos(
\r
1452 detail::root_directory_start<string_type, traits_type>(
\r
1453 itr.m_path_ptr->m_path, end_pos ) );
\r
1455 // if at end and there was a trailing non-root '/', return "."
\r
1456 if ( itr.m_pos == itr.m_path_ptr->m_path.size()
\r
1457 && itr.m_path_ptr->m_path.size() > 1
\r
1458 && itr.m_path_ptr->m_path[itr.m_pos-1] == slash<Path>::value
\r
1459 && detail::is_non_root_slash< string_type, traits_type >(
\r
1460 itr.m_path_ptr->m_path, itr.m_pos-1 )
\r
1464 itr.m_name = dot<Path>::value;
\r
1468 // skip separators unless root directory
\r
1472 && (end_pos-1) != root_dir_pos
\r
1473 && itr.m_path_ptr->m_path[end_pos-1] == slash<Path>::value
\r
1477 itr.m_pos = detail::filename_pos<string_type, traits_type>
\r
1478 ( itr.m_path_ptr->m_path, end_pos );
\r
1479 itr.m_name = itr.m_path_ptr->m_path.substr( itr.m_pos, end_pos - itr.m_pos );
\r
1481 } // namespace detail
\r
1483 // basic_filesystem_error implementation --------------------------------//
\r
1485 template<class Path>
\r
1486 basic_filesystem_error<Path>::basic_filesystem_error(
\r
1487 const std::string & what_arg, system::error_code ec )
\r
1488 : system::system_error(ec, what_arg)
\r
1492 m_imp_ptr.reset( new m_imp );
\r
1494 catch (...) { m_imp_ptr.reset(); }
\r
1497 template<class Path>
\r
1498 basic_filesystem_error<Path>::basic_filesystem_error(
\r
1499 const std::string & what_arg, const path_type & path1_arg,
\r
1500 system::error_code ec )
\r
1501 : system::system_error(ec, what_arg)
\r
1505 m_imp_ptr.reset( new m_imp );
\r
1506 m_imp_ptr->m_path1 = path1_arg;
\r
1508 catch (...) { m_imp_ptr.reset(); }
\r
1511 template<class Path>
\r
1512 basic_filesystem_error<Path>::basic_filesystem_error(
\r
1513 const std::string & what_arg, const path_type & path1_arg,
\r
1514 const path_type & path2_arg, system::error_code ec )
\r
1515 : system::system_error(ec, what_arg)
\r
1519 m_imp_ptr.reset( new m_imp );
\r
1520 m_imp_ptr->m_path1 = path1_arg;
\r
1521 m_imp_ptr->m_path2 = path2_arg;
\r
1523 catch (...) { m_imp_ptr.reset(); }
\r
1526 } // namespace BOOST_FILESYSTEM_NAMESPACE
\r
1527 } // namespace boost
\r
1529 #include <boost/config/abi_suffix.hpp> // pops abi_prefix.hpp pragmas
\r
1531 #endif // BOOST_FILESYSTEM_PATH_HPP
\r