1 // boost/filesystem/path.hpp -----------------------------------------------//
3 // Copyright Beman Dawes 2002-2005
4 // Copyright Vladimir Prus 2002
6 // Distributed under the Boost Software License, Version 1.0. (See accompanying
7 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 // See library home page at http://www.boost.org/libs/filesystem
11 // basic_path's 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.
15 //----------------------------------------------------------------------------//
17 #ifndef BOOST_FILESYSTEM2_PATH_HPP
18 #define BOOST_FILESYSTEM2_PATH_HPP
20 #include <boost/filesystem/v2/config.hpp>
21 #include <boost/system/system_error.hpp>
22 #include <boost/iterator/iterator_facade.hpp>
23 #include <boost/shared_ptr.hpp>
24 #include <boost/type_traits/is_same.hpp>
25 #include <boost/static_assert.hpp>
26 #include <boost/assert.hpp>
29 #include <algorithm> // for lexicographical_compare
30 #include <iosfwd> // needed by basic_path inserter and extractor
33 # ifndef BOOST_FILESYSTEM2_NARROW_ONLY
37 #include <boost/config/abi_prefix.hpp> // must be the last #include
41 namespace BOOST_FILESYSTEM2_NAMESPACE
43 template<class String, class Traits> class basic_path;
46 typedef basic_path< std::string, path_traits > path;
50 typedef std::string internal_string_type;
51 typedef std::string external_string_type;
52 static external_string_type to_external( const path &,
53 const internal_string_type & src ) { return src; }
54 static internal_string_type to_internal(
55 const external_string_type & src ) { return src; }
58 # ifndef BOOST_FILESYSTEM2_NARROW_ONLY
60 struct BOOST_FILESYSTEM_DECL wpath_traits;
62 typedef basic_path< std::wstring, wpath_traits > wpath;
64 struct BOOST_FILESYSTEM_DECL wpath_traits
66 typedef std::wstring internal_string_type;
67 # ifdef BOOST_WINDOWS_API
68 typedef std::wstring external_string_type;
69 static external_string_type to_external( const wpath &,
70 const internal_string_type & src ) { return src; }
71 static internal_string_type to_internal(
72 const external_string_type & src ) { return src; }
74 typedef std::string external_string_type;
75 static external_string_type to_external( const wpath & ph,
76 const internal_string_type & src );
77 static internal_string_type to_internal(
78 const external_string_type & src );
80 static void imbue( const std::locale & loc );
81 static bool imbue( const std::locale & loc, const std::nothrow_t & );
84 # endif // ifndef BOOST_FILESYSTEM2_NARROW_ONLY
86 // path traits ---------------------------------------------------------//
88 template<class Path> struct is_basic_path
89 { BOOST_STATIC_CONSTANT( bool, value = false ); };
90 template<> struct is_basic_path<path>
91 { BOOST_STATIC_CONSTANT( bool, value = true ); };
92 # ifndef BOOST_FILESYSTEM2_NARROW_ONLY
93 template<> struct is_basic_path<wpath>
94 { BOOST_STATIC_CONSTANT( bool, value = true ); };
97 // These only have to be specialized if Path::string_type::value_type
98 // is not convertible from char, although specializations may eliminate
99 // compiler warnings. See ticket 2543.
100 template<class Path> struct slash
101 { BOOST_STATIC_CONSTANT( char, value = '/' ); };
103 template<class Path> struct dot
104 { BOOST_STATIC_CONSTANT( char, value = '.' ); };
106 template<class Path> struct colon
107 { BOOST_STATIC_CONSTANT( char, value = ':' ); };
109 # ifndef BOOST_FILESYSTEM2_NARROW_ONLY
110 template<> struct slash<wpath>
111 { BOOST_STATIC_CONSTANT( wchar_t, value = L'/' ); };
112 template<> struct dot<wpath>
113 { BOOST_STATIC_CONSTANT( wchar_t, value = L'.' ); };
114 template<> struct colon<wpath>
115 { BOOST_STATIC_CONSTANT( wchar_t, value = L':' ); };
118 # ifdef BOOST_WINDOWS_PATH
119 template<class Path> struct path_alt_separator
120 { BOOST_STATIC_CONSTANT( char, value = '\\' ); };
121 # ifndef BOOST_FILESYSTEM2_NARROW_ONLY
122 template<> struct path_alt_separator<wpath>
123 { BOOST_STATIC_CONSTANT( wchar_t, value = L'\\' ); };
127 // workaround for VC++ 7.0 and earlier issues with nested classes
131 class iterator_helper
134 typedef typename Path::iterator iterator;
135 static void do_increment( iterator & ph );
136 static void do_decrement( iterator & ph );
140 // basic_path ----------------------------------------------------------//
142 template<class String, class Traits>
145 // invariant: m_path valid according to the portable generic path grammar
147 // validate template arguments
148 // TODO: get these working
149 // BOOST_STATIC_ASSERT( ::boost::is_same<String,typename Traits::internal_string_type>::value );
150 // 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 );
153 // compiler generates copy constructor and copy assignment
155 typedef basic_path<String, Traits> path_type;
156 typedef String string_type;
157 typedef typename String::value_type value_type;
158 typedef Traits traits_type;
159 typedef typename Traits::external_string_type external_string_type;
161 // constructors/destructor
163 basic_path( const string_type & s ) { operator/=( s ); }
164 basic_path( const value_type * s ) { operator/=( s ); }
165 # ifndef BOOST_NO_MEMBER_TEMPLATES
166 template <class InputIterator>
167 basic_path( InputIterator first, InputIterator last )
168 { append( first, last ); }
173 basic_path & operator=( const string_type & s )
175 # if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, >= 310)
178 m_path.erase( m_path.begin(), m_path.end() );
183 basic_path & operator=( const value_type * s )
185 # if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, >= 310)
188 m_path.erase( m_path.begin(), m_path.end() );
193 # ifndef BOOST_NO_MEMBER_TEMPLATES
194 template <class InputIterator>
195 basic_path & assign( InputIterator first, InputIterator last )
196 { m_path.clear(); append( first, last ); return *this; }
200 basic_path & operator/=( const basic_path & rhs ) { return operator /=( rhs.string().c_str() ); }
201 basic_path & operator/=( const string_type & rhs ) { return operator /=( rhs.c_str() ); }
202 basic_path & operator/=( const value_type * s );
203 # ifndef BOOST_NO_MEMBER_TEMPLATES
204 template <class InputIterator>
205 basic_path & append( InputIterator first, InputIterator last );
210 # if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, >= 310)
213 m_path.erase( m_path.begin(), m_path.end() );
217 void swap( basic_path & rhs )
219 m_path.swap( rhs.m_path );
220 # ifdef BOOST_CYGWIN_PATH
221 std::swap( m_cygwin_root, rhs.m_cygwin_root );
225 basic_path & remove_filename();
226 basic_path & replace_extension( const string_type & new_extension = string_type() );
228 # ifndef BOOST_FILESYSTEM_NO_DEPRECATED
229 basic_path & remove_leaf() { return remove_filename(); }
233 const string_type & string() const { return m_path; }
234 const string_type file_string() const;
235 const string_type directory_string() const { return file_string(); }
237 const external_string_type external_file_string() const { return Traits::to_external( *this, file_string() ); }
238 const external_string_type external_directory_string() const { return Traits::to_external( *this, directory_string() ); }
240 basic_path root_path() const;
241 string_type root_name() const;
242 string_type root_directory() const;
243 basic_path relative_path() const;
244 basic_path parent_path() const;
245 string_type filename() const;
246 string_type stem() const;
247 string_type extension() const;
249 # ifndef BOOST_FILESYSTEM_NO_DEPRECATED
250 string_type leaf() const { return filename(); }
251 basic_path branch_path() const { return parent_path(); }
252 bool has_leaf() const { return !m_path.empty(); }
253 bool has_branch_path() const { return !parent_path().empty(); }
256 bool empty() const { return m_path.empty(); } // name consistent with std containers
257 bool is_complete() const;
258 bool has_root_path() const;
259 bool has_root_name() const;
260 bool has_root_directory() const;
261 bool has_relative_path() const { return !relative_path().empty(); }
262 bool has_filename() const { return !m_path.empty(); }
263 bool has_parent_path() const { return !parent_path().empty(); }
266 class iterator : public boost::iterator_facade<
269 boost::bidirectional_traversal_tag >
272 friend class boost::iterator_core_access;
273 friend class boost::BOOST_FILESYSTEM2_NAMESPACE::basic_path<String, Traits>;
275 const string_type & dereference() const
277 bool equal( const iterator & rhs ) const
278 { return m_path_ptr == rhs.m_path_ptr && m_pos == rhs.m_pos; }
280 friend class boost::BOOST_FILESYSTEM2_NAMESPACE::detail::iterator_helper<path_type>;
284 boost::BOOST_FILESYSTEM2_NAMESPACE::detail::iterator_helper<path_type>::do_increment(
289 boost::BOOST_FILESYSTEM2_NAMESPACE::detail::iterator_helper<path_type>::do_decrement(
293 string_type m_name; // current element
294 const basic_path * m_path_ptr; // path being iterated over
295 typename string_type::size_type m_pos; // position of name in
296 // path_ptr->string(). The
297 // end() iterator is indicated by
298 // pos == path_ptr->m_path.size()
301 typedef iterator const_iterator;
303 iterator begin() const;
304 iterator end() const;
307 // Note: This is an implementation for POSIX and Windows, where there
308 // are only minor differences between generic and native path grammars.
309 // Private members might be quite different in other implementations,
310 // particularly where there were wide differences between portable and
311 // native path formats, or between file_string() and
312 // directory_string() formats, or simply that the implementation
313 // was willing expend additional memory to achieve greater speed for
314 // some operations at the expense of other operations.
316 string_type m_path; // invariant: portable path grammar
317 // on Windows, backslashes converted to slashes
319 # ifdef BOOST_CYGWIN_PATH
320 bool m_cygwin_root; // if present, m_path[0] was slash. note: initialization
324 void m_append_separator_if_needed();
325 void m_append( value_type value ); // converts Windows alt_separator
327 // Was qualified; como433beta8 reports:
328 // warning #427-D: qualified name is not allowed in member declaration
329 friend class iterator;
330 friend class boost::BOOST_FILESYSTEM2_NAMESPACE::detail::iterator_helper<path_type>;
332 // Deprecated features ease transition for existing code. Don't use these
334 # ifndef BOOST_FILESYSTEM_NO_DEPRECATED
336 typedef bool (*name_check)( const std::string & name );
337 basic_path( const string_type & str, name_check ) { operator/=( str ); }
338 basic_path( const typename string_type::value_type * s, name_check )
340 string_type native_file_string() const { return file_string(); }
341 string_type native_directory_string() const { return directory_string(); }
342 static bool default_name_check_writable() { return false; }
343 static void default_name_check( name_check ) {}
344 static name_check default_name_check() { return 0; }
345 basic_path & canonize();
346 basic_path & normalize();
350 // basic_path non-member functions ---------------------------------------//
352 template< class String, class Traits >
353 inline void swap( basic_path<String, Traits> & lhs,
354 basic_path<String, Traits> & rhs ) { lhs.swap( rhs ); }
356 template< class String, class Traits >
357 bool operator<( const basic_path<String, Traits> & lhs, const basic_path<String, Traits> & rhs )
359 return std::lexicographical_compare(
360 lhs.begin(), lhs.end(), rhs.begin(), rhs.end() );
363 template< class String, class Traits >
364 bool operator<( const typename basic_path<String, Traits>::string_type::value_type * lhs,
365 const basic_path<String, Traits> & rhs )
367 basic_path<String, Traits> tmp( lhs );
368 return std::lexicographical_compare(
369 tmp.begin(), tmp.end(), rhs.begin(), rhs.end() );
372 template< class String, class Traits >
373 bool operator<( const typename basic_path<String, Traits>::string_type & lhs,
374 const basic_path<String, Traits> & rhs )
376 basic_path<String, Traits> tmp( lhs );
377 return std::lexicographical_compare(
378 tmp.begin(), tmp.end(), rhs.begin(), rhs.end() );
381 template< class String, class Traits >
382 bool operator<( const basic_path<String, Traits> & lhs,
383 const typename basic_path<String, Traits>::string_type::value_type * rhs )
385 basic_path<String, Traits> tmp( rhs );
386 return std::lexicographical_compare(
387 lhs.begin(), lhs.end(), tmp.begin(), tmp.end() );
390 template< class String, class Traits >
391 bool operator<( const basic_path<String, Traits> & lhs,
392 const typename basic_path<String, Traits>::string_type & rhs )
394 basic_path<String, Traits> tmp( rhs );
395 return std::lexicographical_compare(
396 lhs.begin(), lhs.end(), tmp.begin(), tmp.end() );
399 // operator == uses hand-written compare rather than !(lhs < rhs) && !(rhs < lhs)
400 // because the result is the same yet the direct compare is much more efficient
401 // than lexicographical_compare, which would also be called twice.
403 template< class String, class Traits >
404 inline bool operator==( const basic_path<String, Traits> & lhs,
405 const typename basic_path<String, Traits>::string_type::value_type * rhs )
408 boost::BOOST_FILESYSTEM2_NAMESPACE::basic_path<String, Traits> path_type;
409 const typename path_type::string_type::value_type * l (lhs.string().c_str());
411 # ifdef BOOST_WINDOWS_PATH
412 || (*l == path_alt_separator<path_type>::value && *rhs == slash<path_type>::value)
413 || (*l == slash<path_type>::value && *rhs == path_alt_separator<path_type>::value)
415 ) && *l ) { ++l; ++rhs; }
417 # ifdef BOOST_WINDOWS_PATH
418 || (*l == path_alt_separator<path_type>::value && *rhs == slash<path_type>::value)
419 || (*l == slash<path_type>::value && *rhs == path_alt_separator<path_type>::value)
424 template< class String, class Traits >
425 inline bool operator==( const basic_path<String, Traits> & lhs,
426 const basic_path<String, Traits> & rhs )
428 return lhs == rhs.string().c_str();
431 template< class String, class Traits >
432 inline bool operator==( const typename basic_path<String, Traits>::string_type::value_type * lhs,
433 const basic_path<String, Traits> & rhs )
438 template< class String, class Traits >
439 inline bool operator==( const typename basic_path<String, Traits>::string_type & lhs,
440 const basic_path<String, Traits> & rhs )
442 return rhs == lhs.c_str();
445 template< class String, class Traits >
446 inline bool operator==( const basic_path<String, Traits> & lhs,
447 const typename basic_path<String, Traits>::string_type & rhs )
449 return lhs == rhs.c_str();
452 template< class String, class Traits >
453 inline bool operator!=( const basic_path<String, Traits> & lhs,
454 const basic_path<String, Traits> & rhs )
455 { return !(lhs == rhs); }
457 template< class String, class Traits >
458 inline bool operator!=( const typename basic_path<String,
459 Traits>::string_type::value_type * lhs,
460 const basic_path<String, Traits> & rhs )
461 { return !(lhs == rhs); }
463 template< class String, class Traits >
464 inline bool operator!=( const typename basic_path<String, Traits>::string_type & lhs,
465 const basic_path<String, Traits> & rhs )
466 { return !(lhs == rhs); }
468 template< class String, class Traits >
469 inline bool operator!=( const basic_path<String, Traits> & lhs,
470 const typename basic_path<String, Traits>::string_type::value_type * rhs )
471 { return !(lhs == rhs); }
473 template< class String, class Traits >
474 inline bool operator!=( const basic_path<String, Traits> & lhs,
475 const typename basic_path<String, Traits>::string_type & rhs )
476 { return !(lhs == rhs); }
478 template< class String, class Traits >
479 inline bool operator>( const basic_path<String, Traits> & lhs, const basic_path<String, Traits> & rhs ) { return rhs < lhs; }
481 template< class String, class Traits >
482 inline bool operator>( const typename basic_path<String, Traits>::string_type::value_type * lhs,
483 const basic_path<String, Traits> & rhs ) { return rhs < basic_path<String, Traits>(lhs); }
485 template< class String, class Traits >
486 inline bool operator>( const typename basic_path<String, Traits>::string_type & lhs,
487 const basic_path<String, Traits> & rhs ) { return rhs < basic_path<String, Traits>(lhs); }
489 template< class String, class Traits >
490 inline bool operator>( const basic_path<String, Traits> & lhs,
491 const typename basic_path<String, Traits>::string_type::value_type * rhs )
492 { return basic_path<String, Traits>(rhs) < lhs; }
494 template< class String, class Traits >
495 inline bool operator>( const basic_path<String, Traits> & lhs,
496 const typename basic_path<String, Traits>::string_type & rhs )
497 { return basic_path<String, Traits>(rhs) < lhs; }
499 template< class String, class Traits >
500 inline bool operator<=( const basic_path<String, Traits> & lhs, const basic_path<String, Traits> & rhs ) { return !(rhs < lhs); }
502 template< class String, class Traits >
503 inline bool operator<=( const typename basic_path<String, Traits>::string_type::value_type * lhs,
504 const basic_path<String, Traits> & rhs ) { return !(rhs < basic_path<String, Traits>(lhs)); }
506 template< class String, class Traits >
507 inline bool operator<=( const typename basic_path<String, Traits>::string_type & lhs,
508 const basic_path<String, Traits> & rhs ) { return !(rhs < basic_path<String, Traits>(lhs)); }
510 template< class String, class Traits >
511 inline bool operator<=( const basic_path<String, Traits> & lhs,
512 const typename basic_path<String, Traits>::string_type::value_type * rhs )
513 { return !(basic_path<String, Traits>(rhs) < lhs); }
515 template< class String, class Traits >
516 inline bool operator<=( const basic_path<String, Traits> & lhs,
517 const typename basic_path<String, Traits>::string_type & rhs )
518 { return !(basic_path<String, Traits>(rhs) < lhs); }
520 template< class String, class Traits >
521 inline bool operator>=( const basic_path<String, Traits> & lhs, const basic_path<String, Traits> & rhs ) { return !(lhs < rhs); }
523 template< class String, class Traits >
524 inline bool operator>=( const typename basic_path<String, Traits>::string_type::value_type * lhs,
525 const basic_path<String, Traits> & rhs ) { return !(lhs < basic_path<String, Traits>(rhs)); }
527 template< class String, class Traits >
528 inline bool operator>=( const typename basic_path<String, Traits>::string_type & lhs,
529 const basic_path<String, Traits> & rhs ) { return !(lhs < basic_path<String, Traits>(rhs)); }
531 template< class String, class Traits >
532 inline bool operator>=( const basic_path<String, Traits> & lhs,
533 const typename basic_path<String, Traits>::string_type::value_type * rhs )
534 { return !(basic_path<String, Traits>(lhs) < rhs); }
536 template< class String, class Traits >
537 inline bool operator>=( const basic_path<String, Traits> & lhs,
538 const typename basic_path<String, Traits>::string_type & rhs )
539 { return !(basic_path<String, Traits>(lhs) < rhs); }
543 template< class String, class Traits >
544 inline basic_path<String, Traits> operator/(
545 const basic_path<String, Traits> & lhs,
546 const basic_path<String, Traits> & rhs )
547 { return basic_path<String, Traits>( lhs ) /= rhs; }
549 template< class String, class Traits >
550 inline basic_path<String, Traits> operator/(
551 const basic_path<String, Traits> & lhs,
552 const typename String::value_type * rhs )
553 { return basic_path<String, Traits>( lhs ) /=
554 basic_path<String, Traits>( rhs ); }
556 template< class String, class Traits >
557 inline basic_path<String, Traits> operator/(
558 const basic_path<String, Traits> & lhs, const String & rhs )
559 { return basic_path<String, Traits>( lhs ) /=
560 basic_path<String, Traits>( rhs ); }
562 template< class String, class Traits >
563 inline basic_path<String, Traits> operator/(
564 const typename String::value_type * lhs,
565 const basic_path<String, Traits> & rhs )
566 { return basic_path<String, Traits>( lhs ) /= rhs; }
568 template< class String, class Traits >
569 inline basic_path<String, Traits> operator/(
570 const String & lhs, const basic_path<String, Traits> & rhs )
571 { return basic_path<String, Traits>( lhs ) /= rhs; }
573 // inserters and extractors --------------------------------------------//
575 // bypass VC++ 7.0 and earlier, and broken Borland compilers
576 # if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) && !BOOST_WORKAROUND(__BORLANDC__, < 0x610)
577 template< class Path >
578 std::basic_ostream< typename Path::string_type::value_type,
579 typename Path::string_type::traits_type > &
581 ( std::basic_ostream< typename Path::string_type::value_type,
582 typename Path::string_type::traits_type >& os, const Path & ph )
588 template< class Path >
589 std::basic_istream< typename Path::string_type::value_type,
590 typename Path::string_type::traits_type > &
592 ( std::basic_istream< typename Path::string_type::value_type,
593 typename Path::string_type::traits_type >& is, Path & ph )
595 typename Path::string_type str;
596 std::getline(is, str); // See ticket 3863
600 # elif BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
601 template< class String, class Traits >
602 std::basic_ostream< BOOST_DEDUCED_TYPENAME String::value_type,
603 BOOST_DEDUCED_TYPENAME String::traits_type > &
605 ( std::basic_ostream< BOOST_DEDUCED_TYPENAME String::value_type,
606 BOOST_DEDUCED_TYPENAME String::traits_type >& os,
607 const basic_path< String, Traits > & ph )
613 template< class String, class Traits >
614 std::basic_istream< BOOST_DEDUCED_TYPENAME String::value_type,
615 BOOST_DEDUCED_TYPENAME String::traits_type > &
617 ( std::basic_istream< BOOST_DEDUCED_TYPENAME String::value_type,
618 BOOST_DEDUCED_TYPENAME String::traits_type> & is,
619 basic_path< String, Traits > & ph )
622 std::getline(is, str); // See ticket 3863
628 // basic_filesystem_error helpers --------------------------------------//
630 // Originally choice of implementation was done via specialization of
631 // basic_filesystem_error::what(). Several compilers (GCC, aCC, etc.)
632 // couldn't handle that, so the choice is now accomplished by overloading.
636 // BOOST_FILESYSTEM_DECL version works for VC++ but not GCC. Go figure!
638 const char * what( const char * sys_err_what,
639 const path & path1_arg, const path & path2_arg, std::string & target )
643 if ( target.empty() )
645 target = sys_err_what;
646 if ( !path1_arg.empty() )
649 target += path1_arg.file_string();
652 if ( !path2_arg.empty() )
655 target += path2_arg.file_string();
659 return target.c_str();
668 const char * what( const char * sys_err_what,
669 const Path & /*path1_arg*/, const Path & /*path2_arg*/, std::string & /*target*/ )
675 // basic_filesystem_error ----------------------------------------------//
678 class basic_filesystem_error : public system::system_error
680 // see http://www.boost.org/more/error_handling.html for design rationale
682 // compiler generates copy constructor and copy assignment
684 typedef Path path_type;
686 basic_filesystem_error( const std::string & what_arg,
687 system::error_code ec );
689 basic_filesystem_error( const std::string & what_arg,
690 const path_type & path1_arg, system::error_code ec );
692 basic_filesystem_error( const std::string & what_arg, const path_type & path1_arg,
693 const path_type & path2_arg, system::error_code ec );
695 ~basic_filesystem_error() throw() {}
697 const path_type & path1() const
699 static const path_type empty_path;
700 return m_imp_ptr.get() ? m_imp_ptr->m_path1 : empty_path ;
702 const path_type & path2() const
704 static const path_type empty_path;
705 return m_imp_ptr.get() ? m_imp_ptr->m_path2 : empty_path ;
708 const char * what() const throw()
710 if ( !m_imp_ptr.get() )
711 return system::system_error::what();
712 return detail::what( system::system_error::what(), m_imp_ptr->m_path1,
713 m_imp_ptr->m_path2, m_imp_ptr->m_what );
719 path_type m_path1; // may be empty()
720 path_type m_path2; // may be empty()
721 std::string m_what; // not built until needed
723 boost::shared_ptr<m_imp> m_imp_ptr;
726 typedef basic_filesystem_error<path> filesystem_error;
728 # ifndef BOOST_FILESYSTEM2_NARROW_ONLY
729 typedef basic_filesystem_error<wpath> wfilesystem_error;
732 // path::name_checks -----------------------------------------------------//
734 BOOST_FILESYSTEM_DECL bool portable_posix_name( const std::string & name );
735 BOOST_FILESYSTEM_DECL bool windows_name( const std::string & name );
736 BOOST_FILESYSTEM_DECL bool portable_name( const std::string & name );
737 BOOST_FILESYSTEM_DECL bool portable_directory_name( const std::string & name );
738 BOOST_FILESYSTEM_DECL bool portable_file_name( const std::string & name );
739 BOOST_FILESYSTEM_DECL bool native( const std::string & name );
740 inline bool no_check( const std::string & )
743 // implementation -----------------------------------------------------------//
748 // is_separator helper ------------------------------------------------//
751 inline bool is_separator( typename Path::string_type::value_type c )
753 return c == slash<Path>::value
754 # ifdef BOOST_WINDOWS_PATH
755 || c == path_alt_separator<Path>::value
760 // filename_pos helper ----------------------------------------------------//
762 template<class String, class Traits>
763 typename String::size_type filename_pos(
764 const String & str, // precondition: portable generic path grammar
765 typename String::size_type end_pos ) // end_pos is past-the-end position
766 // return 0 if str itself is filename (or empty)
769 boost::BOOST_FILESYSTEM2_NAMESPACE::basic_path<String, Traits> path_type;
773 && str[0] == slash<path_type>::value
774 && str[1] == slash<path_type>::value ) return 0;
777 if ( end_pos && str[end_pos-1] == slash<path_type>::value )
780 // set pos to start of last element
781 typename String::size_type pos(
782 str.find_last_of( slash<path_type>::value, end_pos-1 ) );
783 # ifdef BOOST_WINDOWS_PATH
784 if ( pos == String::npos )
785 pos = str.find_last_of( path_alt_separator<path_type>::value, end_pos-1 );
786 if ( pos == String::npos )
787 pos = str.find_last_of( colon<path_type>::value, end_pos-2 );
790 return ( pos == String::npos // path itself must be a filename (or empty)
791 || (pos == 1 && str[0] == slash<path_type>::value) ) // or net
792 ? 0 // so filename is entire string
793 : pos + 1; // or starts after delimiter
796 // first_element helper -----------------------------------------------//
797 // sets pos and len of first element, excluding extra separators
798 // if src.empty(), sets pos,len, to 0,0.
800 template<class String, class Traits>
802 const String & src, // precondition: portable generic path grammar
803 typename String::size_type & element_pos,
804 typename String::size_type & element_size,
805 # if !BOOST_WORKAROUND( BOOST_MSVC, <= 1310 ) // VC++ 7.1
806 typename String::size_type size = String::npos
808 typename String::size_type size = -1
812 if ( size == String::npos ) size = src.size();
815 if ( src.empty() ) return;
817 typedef typename boost::BOOST_FILESYSTEM2_NAMESPACE::basic_path<String, Traits> path_type;
819 typename String::size_type cur(0);
821 // deal with // [network]
822 if ( size >= 2 && src[0] == slash<path_type>::value
823 && src[1] == slash<path_type>::value
825 || src[2] != slash<path_type>::value) )
831 // leading (not non-network) separator
832 else if ( src[0] == slash<path_type>::value )
835 // bypass extra leading separators
837 && src[cur+1] == slash<path_type>::value )
845 // at this point, we have either a plain name, a network name,
846 // or (on Windows only) a device name
850 # ifdef BOOST_WINDOWS_PATH
851 && src[cur] != colon<path_type>::value
853 && src[cur] != slash<path_type>::value )
859 # ifdef BOOST_WINDOWS_PATH
860 if ( cur == size ) return;
861 // include device delimiter
862 if ( src[cur] == colon<path_type>::value )
869 // root_directory_start helper ----------------------------------------//
871 template<class String, class Traits>
872 typename String::size_type root_directory_start(
873 const String & s, // precondition: portable generic path grammar
874 typename String::size_type size )
875 // return npos if no root_directory found
877 typedef typename boost::BOOST_FILESYSTEM2_NAMESPACE::basic_path<String, Traits> path_type;
879 # ifdef BOOST_WINDOWS_PATH
882 && s[1] == colon<path_type>::value
883 && s[2] == slash<path_type>::value ) return 2;
888 && s[0] == slash<path_type>::value
889 && s[1] == slash<path_type>::value ) return String::npos;
893 && s[0] == slash<path_type>::value
894 && s[1] == slash<path_type>::value
895 && s[2] != slash<path_type>::value )
897 typename String::size_type pos(
898 s.find( slash<path_type>::value, 2 ) );
899 return pos < size ? pos : String::npos;
903 if ( size > 0 && s[0] == slash<path_type>::value ) return 0;
908 // is_non_root_slash helper -------------------------------------------//
910 template<class String, class Traits>
911 bool is_non_root_slash( const String & str,
912 typename String::size_type pos ) // pos is position of the slash
915 boost::BOOST_FILESYSTEM2_NAMESPACE::basic_path<String, Traits>
918 BOOST_ASSERT( !str.empty() && str[pos] == slash<path_type>::value
919 && "precondition violation" );
921 // subsequent logic expects pos to be for leftmost slash of a set
922 while ( pos > 0 && str[pos-1] == slash<path_type>::value )
926 && (pos <= 2 || str[1] != slash<path_type>::value
927 || str.find( slash<path_type>::value, 2 ) != pos)
928 # ifdef BOOST_WINDOWS_PATH
929 && (pos !=2 || str[1] != colon<path_type>::value)
933 } // namespace detail
935 // decomposition functions ----------------------------------------------//
937 template<class String, class Traits>
938 String basic_path<String, Traits>::filename() const
940 typename String::size_type end_pos(
941 detail::filename_pos<String, Traits>( m_path, m_path.size() ) );
942 return (m_path.size()
944 && m_path[end_pos] == slash<path_type>::value
945 && detail::is_non_root_slash< String, Traits >(m_path, end_pos))
946 ? String( 1, dot<path_type>::value )
947 : m_path.substr( end_pos );
950 template<class String, class Traits>
951 String basic_path<String, Traits>::stem() const
953 string_type name = filename();
954 typename string_type::size_type n = name.rfind(dot<path_type>::value);
955 return name.substr(0, n);
958 template<class String, class Traits>
959 String basic_path<String, Traits>::extension() const
961 string_type name = filename();
962 typename string_type::size_type n = name.rfind(dot<path_type>::value);
963 if (n != string_type::npos)
964 return name.substr(n);
966 return string_type();
969 template<class String, class Traits>
970 basic_path<String, Traits> basic_path<String, Traits>::parent_path() const
972 typename String::size_type end_pos(
973 detail::filename_pos<String, Traits>( m_path, m_path.size() ) );
975 bool filename_was_separator( m_path.size()
976 && m_path[end_pos] == slash<path_type>::value );
978 // skip separators unless root directory
979 typename string_type::size_type root_dir_pos( detail::root_directory_start
980 <string_type, traits_type>( m_path, end_pos ) );
983 && (end_pos-1) != root_dir_pos
984 && m_path[end_pos-1] == slash<path_type>::value
988 return (end_pos == 1 && root_dir_pos == 0 && filename_was_separator)
990 : path_type( m_path.substr( 0, end_pos ) );
993 template<class String, class Traits>
994 basic_path<String, Traits> basic_path<String, Traits>::relative_path() const
996 iterator itr( begin() );
997 for ( ; itr.m_pos != m_path.size()
998 && (itr.m_name[0] == slash<path_type>::value
999 # ifdef BOOST_WINDOWS_PATH
1000 || itr.m_name[itr.m_name.size()-1]
1001 == colon<path_type>::value
1005 return basic_path<String, Traits>( m_path.substr( itr.m_pos ) );
1008 template<class String, class Traits>
1009 String basic_path<String, Traits>::root_name() const
1011 iterator itr( begin() );
1013 return ( itr.m_pos != m_path.size()
1015 ( itr.m_name.size() > 1
1016 && itr.m_name[0] == slash<path_type>::value
1017 && itr.m_name[1] == slash<path_type>::value
1019 # ifdef BOOST_WINDOWS_PATH
1020 || itr.m_name[itr.m_name.size()-1]
1021 == colon<path_type>::value
1028 template<class String, class Traits>
1029 String basic_path<String, Traits>::root_directory() const
1031 typename string_type::size_type start(
1032 detail::root_directory_start<String, Traits>( m_path, m_path.size() ) );
1034 return start == string_type::npos
1036 : m_path.substr( start, 1 );
1039 template<class String, class Traits>
1040 basic_path<String, Traits> basic_path<String, Traits>::root_path() const
1042 // even on POSIX, root_name() is non-empty() on network paths
1043 return basic_path<String, Traits>( root_name() ) /= root_directory();
1046 // path query functions -------------------------------------------------//
1048 template<class String, class Traits>
1049 inline bool basic_path<String, Traits>::is_complete() const
1051 # ifdef BOOST_WINDOWS_PATH
1052 return has_root_name() && has_root_directory();
1054 return has_root_directory();
1058 template<class String, class Traits>
1059 inline bool basic_path<String, Traits>::has_root_path() const
1061 return !root_path().empty();
1064 template<class String, class Traits>
1065 inline bool basic_path<String, Traits>::has_root_name() const
1067 return !root_name().empty();
1070 template<class String, class Traits>
1071 inline bool basic_path<String, Traits>::has_root_directory() const
1073 return !root_directory().empty();
1076 // append ---------------------------------------------------------------//
1078 template<class String, class Traits>
1079 void basic_path<String, Traits>::m_append_separator_if_needed()
1080 // requires: !empty()
1083 # ifdef BOOST_WINDOWS_PATH
1084 *(m_path.end()-1) != colon<path_type>::value &&
1086 *(m_path.end()-1) != slash<path_type>::value )
1088 m_path += slash<path_type>::value;
1092 template<class String, class Traits>
1093 void basic_path<String, Traits>::m_append( value_type value )
1095 # ifdef BOOST_CYGWIN_PATH
1096 if ( m_path.empty() ) m_cygwin_root = (value == slash<path_type>::value);
1099 # ifdef BOOST_WINDOWS_PATH
1100 // for BOOST_WINDOWS_PATH, convert alt_separator ('\') to separator ('/')
1101 m_path += ( value == path_alt_separator<path_type>::value
1102 ? slash<path_type>::value
1109 // except that it wouldn't work for BOOST_NO_MEMBER_TEMPLATES compilers,
1110 // the append() member template could replace this code.
1111 template<class String, class Traits>
1112 basic_path<String, Traits> & basic_path<String, Traits>::operator /=
1113 ( const value_type * next_p )
1115 // ignore escape sequence on POSIX or Windows
1116 if ( *next_p == slash<path_type>::value
1117 && *(next_p+1) == slash<path_type>::value
1118 && *(next_p+2) == colon<path_type>::value ) next_p += 3;
1120 // append slash<path_type>::value if needed
1121 if ( !empty() && *next_p != 0
1122 && !detail::is_separator<path_type>( *next_p ) )
1123 { m_append_separator_if_needed(); }
1125 for ( ; *next_p != 0; ++next_p ) m_append( *next_p );
1129 # ifndef BOOST_NO_MEMBER_TEMPLATES
1130 template<class String, class Traits> template <class InputIterator>
1131 basic_path<String, Traits> & basic_path<String, Traits>::append(
1132 InputIterator first, InputIterator last )
1134 // append slash<path_type>::value if needed
1135 if ( !empty() && first != last
1136 && !detail::is_separator<path_type>( *first ) )
1137 { m_append_separator_if_needed(); }
1139 // song-and-dance to avoid violating InputIterator requirements
1140 // (which prohibit lookahead) in detecting a possible escape sequence
1141 // (escape sequences are simply ignored on POSIX and Windows)
1142 bool was_escape_sequence(true);
1143 std::size_t append_count(0);
1144 typename String::size_type initial_pos( m_path.size() );
1146 for ( ; first != last && *first; ++first )
1148 if ( append_count == 0 && *first != slash<path_type>::value )
1149 was_escape_sequence = false;
1150 if ( append_count == 1 && *first != slash<path_type>::value )
1151 was_escape_sequence = false;
1152 if ( append_count == 2 && *first != colon<path_type>::value )
1153 was_escape_sequence = false;
1158 // erase escape sequence if any
1159 if ( was_escape_sequence && append_count >= 3 )
1160 m_path.erase( initial_pos, 3 );
1166 # ifndef BOOST_FILESYSTEM_NO_DEPRECATED
1168 // canonize ------------------------------------------------------------//
1170 template<class String, class Traits>
1171 basic_path<String, Traits> & basic_path<String, Traits>::canonize()
1173 static const typename string_type::value_type dot_str[]
1174 = { dot<path_type>::value, 0 };
1176 if ( m_path.empty() ) return *this;
1180 for ( iterator itr( begin() ); itr != end(); ++itr )
1185 if ( temp.empty() ) temp /= dot_str;
1186 m_path = temp.m_path;
1190 // normalize ------------------------------------------------------------//
1192 template<class String, class Traits>
1193 basic_path<String, Traits> & basic_path<String, Traits>::normalize()
1195 static const typename string_type::value_type dot_str[]
1196 = { dot<path_type>::value, 0 };
1198 if ( m_path.empty() ) return *this;
1201 iterator start( begin() );
1202 iterator last( end() );
1203 iterator stop( last-- );
1204 for ( iterator itr( start ); itr != stop; ++itr )
1206 // ignore "." except at start and last
1207 if ( itr->size() == 1
1208 && (*itr)[0] == dot<path_type>::value
1210 && itr != last ) continue;
1212 // ignore a name and following ".."
1215 && (*itr)[0] == dot<path_type>::value
1216 && (*itr)[1] == dot<path_type>::value ) // dot dot
1218 string_type lf( temp.filename() );
1221 || (lf[0] != dot<path_type>::value
1222 && lf[0] != slash<path_type>::value))
1224 || (lf[0] != dot<path_type>::value
1225 && lf[1] != dot<path_type>::value
1226 # ifdef BOOST_WINDOWS_PATH
1227 && lf[1] != colon<path_type>::value
1233 temp.remove_filename();
1234 // if not root directory, must also remove "/" if any
1235 if ( temp.m_path.size() > 0
1236 && temp.m_path[temp.m_path.size()-1]
1237 == slash<path_type>::value )
1239 typename string_type::size_type rds(
1240 detail::root_directory_start<String,Traits>( temp.m_path,
1241 temp.m_path.size() ) );
1242 if ( rds == string_type::npos
1243 || rds != temp.m_path.size()-1 )
1244 { temp.m_path.erase( temp.m_path.size()-1 ); }
1247 iterator next( itr );
1248 if ( temp.empty() && ++next != stop
1249 && next == last && *last == dot_str ) temp /= dot_str;
1257 if ( temp.empty() ) temp /= dot_str;
1258 m_path = temp.m_path;
1264 // modifiers ------------------------------------------------------------//
1266 template<class String, class Traits>
1267 basic_path<String, Traits> & basic_path<String, Traits>::remove_filename()
1270 detail::filename_pos<String, Traits>( m_path, m_path.size() ) );
1274 template<class String, class Traits>
1275 basic_path<String, Traits> &
1276 basic_path<String, Traits>::replace_extension( const string_type & new_ext )
1278 // erase existing extension if any
1279 string_type old_ext = extension();
1280 if ( !old_ext.empty() )
1281 m_path.erase( m_path.size() - old_ext.size() );
1283 if ( !new_ext.empty() && new_ext[0] != dot<path_type>::value )
1284 m_path += dot<path_type>::value;
1292 // path conversion functions --------------------------------------------//
1294 template<class String, class Traits>
1296 basic_path<String, Traits>::file_string() const
1298 # ifdef BOOST_WINDOWS_PATH
1299 // for Windows, use the alternate separator, and bypass extra
1302 typename string_type::size_type root_dir_start(
1303 detail::root_directory_start<String, Traits>( m_path, m_path.size() ) );
1304 bool in_root( root_dir_start != string_type::npos );
1306 for ( typename string_type::size_type pos( 0 );
1307 pos != m_path.size(); ++pos )
1309 // special case // [net]
1310 if ( pos == 0 && m_path.size() > 1
1311 && m_path[0] == slash<path_type>::value
1312 && m_path[1] == slash<path_type>::value
1313 && ( m_path.size() == 2
1314 || !detail::is_separator<path_type>( m_path[2] )
1318 s += path_alt_separator<path_type>::value;
1319 s += path_alt_separator<path_type>::value;
1323 // bypass extra root separators
1327 && s[s.size()-1] == path_alt_separator<path_type>::value
1328 && m_path[pos] == slash<path_type>::value
1332 if ( m_path[pos] == slash<path_type>::value )
1333 s += path_alt_separator<path_type>::value;
1337 if ( pos > root_dir_start
1338 && m_path[pos] == slash<path_type>::value )
1339 { in_root = false; }
1341 # ifdef BOOST_CYGWIN_PATH
1342 if ( m_cygwin_root ) s[0] = slash<path_type>::value;
1350 // iterator functions ---------------------------------------------------//
1352 template<class String, class Traits>
1353 typename basic_path<String, Traits>::iterator basic_path<String, Traits>::begin() const
1356 itr.m_path_ptr = this;
1357 typename string_type::size_type element_size;
1358 detail::first_element<String, Traits>( m_path, itr.m_pos, element_size );
1359 itr.m_name = m_path.substr( itr.m_pos, element_size );
1363 template<class String, class Traits>
1364 typename basic_path<String, Traits>::iterator basic_path<String, Traits>::end() const
1367 itr.m_path_ptr = this;
1368 itr.m_pos = m_path.size();
1374 // do_increment ------------------------------------------------------//
1376 template<class Path>
1377 void iterator_helper<Path>::do_increment( iterator & itr )
1379 typedef typename Path::string_type string_type;
1380 typedef typename Path::traits_type traits_type;
1382 BOOST_ASSERT( itr.m_pos < itr.m_path_ptr->m_path.size() && "basic_path::iterator increment past end()" );
1384 bool was_net( itr.m_name.size() > 2
1385 && itr.m_name[0] == slash<Path>::value
1386 && itr.m_name[1] == slash<Path>::value
1387 && itr.m_name[2] != slash<Path>::value );
1389 // increment to position past current element
1390 itr.m_pos += itr.m_name.size();
1392 // if end reached, create end iterator
1393 if ( itr.m_pos == itr.m_path_ptr->m_path.size() )
1395 itr.m_name.erase( itr.m_name.begin(), itr.m_name.end() ); // VC++ 6.0 lib didn't supply clear()
1399 // process separator (Windows drive spec is only case not a separator)
1400 if ( itr.m_path_ptr->m_path[itr.m_pos] == slash<Path>::value )
1402 // detect root directory
1404 # ifdef BOOST_WINDOWS_PATH
1406 || itr.m_name[itr.m_name.size()-1] == colon<Path>::value
1410 itr.m_name = slash<Path>::value;
1414 // bypass separators
1415 while ( itr.m_pos != itr.m_path_ptr->m_path.size()
1416 && itr.m_path_ptr->m_path[itr.m_pos] == slash<Path>::value )
1419 // detect trailing separator, and treat it as ".", per POSIX spec
1420 if ( itr.m_pos == itr.m_path_ptr->m_path.size()
1421 && detail::is_non_root_slash< string_type, traits_type >(
1422 itr.m_path_ptr->m_path, itr.m_pos-1 ) )
1425 itr.m_name = dot<Path>::value;
1431 typename string_type::size_type end_pos(
1432 itr.m_path_ptr->m_path.find( slash<Path>::value, itr.m_pos ) );
1433 itr.m_name = itr.m_path_ptr->m_path.substr( itr.m_pos, end_pos - itr.m_pos );
1436 // do_decrement ------------------------------------------------------//
1438 template<class Path>
1439 void iterator_helper<Path>::do_decrement( iterator & itr )
1441 BOOST_ASSERT( itr.m_pos && "basic_path::iterator decrement past begin()" );
1443 typedef typename Path::string_type string_type;
1444 typedef typename Path::traits_type traits_type;
1446 typename string_type::size_type end_pos( itr.m_pos );
1448 typename string_type::size_type root_dir_pos(
1449 detail::root_directory_start<string_type, traits_type>(
1450 itr.m_path_ptr->m_path, end_pos ) );
1452 // if at end and there was a trailing non-root '/', return "."
1453 if ( itr.m_pos == itr.m_path_ptr->m_path.size()
1454 && itr.m_path_ptr->m_path.size() > 1
1455 && itr.m_path_ptr->m_path[itr.m_pos-1] == slash<Path>::value
1456 && detail::is_non_root_slash< string_type, traits_type >(
1457 itr.m_path_ptr->m_path, itr.m_pos-1 )
1461 itr.m_name = dot<Path>::value;
1465 // skip separators unless root directory
1469 && (end_pos-1) != root_dir_pos
1470 && itr.m_path_ptr->m_path[end_pos-1] == slash<Path>::value
1474 itr.m_pos = detail::filename_pos<string_type, traits_type>
1475 ( itr.m_path_ptr->m_path, end_pos );
1476 itr.m_name = itr.m_path_ptr->m_path.substr( itr.m_pos, end_pos - itr.m_pos );
1478 } // namespace detail
1480 // basic_filesystem_error implementation --------------------------------//
1482 template<class Path>
1483 basic_filesystem_error<Path>::basic_filesystem_error(
1484 const std::string & what_arg, system::error_code ec )
1485 : system::system_error(ec, what_arg)
1489 m_imp_ptr.reset( new m_imp );
1491 catch (...) { m_imp_ptr.reset(); }
1494 template<class Path>
1495 basic_filesystem_error<Path>::basic_filesystem_error(
1496 const std::string & what_arg, const path_type & path1_arg,
1497 system::error_code ec )
1498 : system::system_error(ec, what_arg)
1502 m_imp_ptr.reset( new m_imp );
1503 m_imp_ptr->m_path1 = path1_arg;
1505 catch (...) { m_imp_ptr.reset(); }
1508 template<class Path>
1509 basic_filesystem_error<Path>::basic_filesystem_error(
1510 const std::string & what_arg, const path_type & path1_arg,
1511 const path_type & path2_arg, system::error_code ec )
1512 : system::system_error(ec, what_arg)
1516 m_imp_ptr.reset( new m_imp );
1517 m_imp_ptr->m_path1 = path1_arg;
1518 m_imp_ptr->m_path2 = path2_arg;
1520 catch (...) { m_imp_ptr.reset(); }
1523 } // namespace BOOST_FILESYSTEM2_NAMESPACE
1524 } // namespace boost
1526 //----------------------------------------------------------------------------//
1530 namespace filesystem
1532 using filesystem2::basic_path;
1533 using filesystem2::path_traits;
1535 using filesystem2::slash;
1536 using filesystem2::dot;
1537 using filesystem2::colon;
1539 using filesystem2::path;
1540 # ifndef BOOST_FILESYSTEM2_NARROW_ONLY
1541 using filesystem2::wpath_traits;
1542 using filesystem2::wpath;
1543 using filesystem2::wfilesystem_error;
1545 using filesystem2::basic_filesystem_error;
1546 using filesystem2::filesystem_error;
1547 using filesystem2::portable_posix_name;
1548 using filesystem2::windows_name;
1549 using filesystem2::portable_name;
1550 using filesystem2::portable_directory_name;
1551 using filesystem2::portable_file_name;
1552 using filesystem2::native;
1553 using filesystem2::no_check;
1554 using filesystem2::swap;
1555 using filesystem2::operator<;
1556 using filesystem2::operator==;
1557 using filesystem2::operator!=;
1558 using filesystem2::operator>;
1559 using filesystem2::operator<=;
1560 using filesystem2::operator>=;
1561 using filesystem2::operator/;
1562 using filesystem2::operator<<;
1563 using filesystem2::operator>>;
1567 //----------------------------------------------------------------------------//
1569 #include <boost/config/abi_suffix.hpp> // pops abi_prefix.hpp pragmas
1571 #endif // BOOST_FILESYSTEM2_PATH_HPP