| // boost/filesystem/path.hpp -----------------------------------------------// |
| |
| // Copyright Beman Dawes 2002-2005 |
| // Copyright Vladimir Prus 2002 |
| |
| // Distributed under the Boost Software License, Version 1.0. (See accompanying |
| // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| |
| // See library home page at http://www.boost.org/libs/filesystem |
| |
| // basic_path's stem(), extension(), and replace_extension() are based on |
| // basename(), extension(), and change_extension() from the original |
| // filesystem/convenience.hpp header by Vladimir Prus. |
| |
| //----------------------------------------------------------------------------// |
| |
| #ifndef BOOST_FILESYSTEM2_PATH_HPP |
| #define BOOST_FILESYSTEM2_PATH_HPP |
| |
| #include <boost/filesystem/v2/config.hpp> |
| #include <boost/system/system_error.hpp> |
| #include <boost/iterator/iterator_facade.hpp> |
| #include <boost/throw_exception.hpp> |
| #include <boost/shared_ptr.hpp> |
| #include <boost/type_traits/is_same.hpp> |
| #include <boost/static_assert.hpp> |
| |
| #include <string> |
| #include <algorithm> // for lexicographical_compare |
| #include <iosfwd> // needed by basic_path inserter and extractor |
| #include <stdexcept> |
| #include <cassert> |
| |
| # ifndef BOOST_FILESYSTEM2_NARROW_ONLY |
| # include <locale> |
| # endif |
| |
| #include <boost/config/abi_prefix.hpp> // must be the last #include |
| |
| namespace boost |
| { |
| namespace BOOST_FILESYSTEM2_NAMESPACE |
| { |
| template<class String, class Traits> class basic_path; |
| |
| struct path_traits; |
| typedef basic_path< std::string, path_traits > path; |
| |
| struct path_traits |
| { |
| typedef std::string internal_string_type; |
| typedef std::string external_string_type; |
| static external_string_type to_external( const path &, |
| const internal_string_type & src ) { return src; } |
| static internal_string_type to_internal( |
| const external_string_type & src ) { return src; } |
| }; |
| |
| # ifndef BOOST_FILESYSTEM2_NARROW_ONLY |
| |
| struct BOOST_FILESYSTEM_DECL wpath_traits; |
| |
| typedef basic_path< std::wstring, wpath_traits > wpath; |
| |
| struct BOOST_FILESYSTEM_DECL wpath_traits |
| { |
| typedef std::wstring internal_string_type; |
| # ifdef BOOST_WINDOWS_API |
| typedef std::wstring external_string_type; |
| static external_string_type to_external( const wpath &, |
| const internal_string_type & src ) { return src; } |
| static internal_string_type to_internal( |
| const external_string_type & src ) { return src; } |
| # else |
| typedef std::string external_string_type; |
| static external_string_type to_external( const wpath & ph, |
| const internal_string_type & src ); |
| static internal_string_type to_internal( |
| const external_string_type & src ); |
| # endif |
| static void imbue( const std::locale & loc ); |
| static bool imbue( const std::locale & loc, const std::nothrow_t & ); |
| }; |
| |
| # endif // ifndef BOOST_FILESYSTEM2_NARROW_ONLY |
| |
| // path traits ---------------------------------------------------------// |
| |
| template<class Path> struct is_basic_path |
| { BOOST_STATIC_CONSTANT( bool, value = false ); }; |
| template<> struct is_basic_path<path> |
| { BOOST_STATIC_CONSTANT( bool, value = true ); }; |
| # ifndef BOOST_FILESYSTEM2_NARROW_ONLY |
| template<> struct is_basic_path<wpath> |
| { BOOST_STATIC_CONSTANT( bool, value = true ); }; |
| # endif |
| |
| // These only have to be specialized if Path::string_type::value_type |
| // is not convertible from char, although specializations may eliminate |
| // compiler warnings. See ticket 2543. |
| template<class Path> struct slash |
| { BOOST_STATIC_CONSTANT( char, value = '/' ); }; |
| |
| template<class Path> struct dot |
| { BOOST_STATIC_CONSTANT( char, value = '.' ); }; |
| |
| template<class Path> struct colon |
| { BOOST_STATIC_CONSTANT( char, value = ':' ); }; |
| |
| # ifndef BOOST_FILESYSTEM2_NARROW_ONLY |
| template<> struct slash<wpath> |
| { BOOST_STATIC_CONSTANT( wchar_t, value = L'/' ); }; |
| template<> struct dot<wpath> |
| { BOOST_STATIC_CONSTANT( wchar_t, value = L'.' ); }; |
| template<> struct colon<wpath> |
| { BOOST_STATIC_CONSTANT( wchar_t, value = L':' ); }; |
| # endif |
| |
| # ifdef BOOST_WINDOWS_PATH |
| template<class Path> struct path_alt_separator |
| { BOOST_STATIC_CONSTANT( char, value = '\\' ); }; |
| # ifndef BOOST_FILESYSTEM2_NARROW_ONLY |
| template<> struct path_alt_separator<wpath> |
| { BOOST_STATIC_CONSTANT( wchar_t, value = L'\\' ); }; |
| # endif |
| # endif |
| |
| // workaround for VC++ 7.0 and earlier issues with nested classes |
| namespace detail |
| { |
| template<class Path> |
| class iterator_helper |
| { |
| public: |
| typedef typename Path::iterator iterator; |
| static void do_increment( iterator & ph ); |
| static void do_decrement( iterator & ph ); |
| }; |
| } |
| |
| // basic_path ----------------------------------------------------------// |
| |
| template<class String, class Traits> |
| class basic_path |
| { |
| // invariant: m_path valid according to the portable generic path grammar |
| |
| // validate template arguments |
| // TODO: get these working |
| // BOOST_STATIC_ASSERT( ::boost::is_same<String,typename Traits::internal_string_type>::value ); |
| // 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 ); |
| |
| public: |
| // compiler generates copy constructor and copy assignment |
| |
| typedef basic_path<String, Traits> path_type; |
| typedef String string_type; |
| typedef typename String::value_type value_type; |
| typedef Traits traits_type; |
| typedef typename Traits::external_string_type external_string_type; |
| |
| // constructors/destructor |
| basic_path() {} |
| basic_path( const string_type & s ) { operator/=( s ); } |
| basic_path( const value_type * s ) { operator/=( s ); } |
| # ifndef BOOST_NO_MEMBER_TEMPLATES |
| template <class InputIterator> |
| basic_path( InputIterator first, InputIterator last ) |
| { append( first, last ); } |
| # endif |
| ~basic_path() {} |
| |
| // assignments |
| basic_path & operator=( const string_type & s ) |
| { |
| # if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, >= 310) |
| m_path.clear(); |
| # else |
| m_path.erase( m_path.begin(), m_path.end() ); |
| # endif |
| operator/=( s ); |
| return *this; |
| } |
| basic_path & operator=( const value_type * s ) |
| { |
| # if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, >= 310) |
| m_path.clear(); |
| # else |
| m_path.erase( m_path.begin(), m_path.end() ); |
| # endif |
| operator/=( s ); |
| return *this; |
| } |
| # ifndef BOOST_NO_MEMBER_TEMPLATES |
| template <class InputIterator> |
| basic_path & assign( InputIterator first, InputIterator last ) |
| { m_path.clear(); append( first, last ); return *this; } |
| # endif |
| |
| // modifiers |
| basic_path & operator/=( const basic_path & rhs ) { return operator /=( rhs.string().c_str() ); } |
| basic_path & operator/=( const string_type & rhs ) { return operator /=( rhs.c_str() ); } |
| basic_path & operator/=( const value_type * s ); |
| # ifndef BOOST_NO_MEMBER_TEMPLATES |
| template <class InputIterator> |
| basic_path & append( InputIterator first, InputIterator last ); |
| # endif |
| |
| void clear() |
| { |
| # if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, >= 310) |
| m_path.clear(); |
| # else |
| m_path.erase( m_path.begin(), m_path.end() ); |
| # endif |
| } |
| |
| void swap( basic_path & rhs ) |
| { |
| m_path.swap( rhs.m_path ); |
| # ifdef BOOST_CYGWIN_PATH |
| std::swap( m_cygwin_root, rhs.m_cygwin_root ); |
| # endif |
| } |
| |
| basic_path & remove_filename(); |
| basic_path & replace_extension( const string_type & new_extension = string_type() ); |
| |
| # ifndef BOOST_FILESYSTEM_NO_DEPRECATED |
| basic_path & remove_leaf() { return remove_filename(); } |
| # endif |
| |
| // observers |
| const string_type & string() const { return m_path; } |
| const string_type file_string() const; |
| const string_type directory_string() const { return file_string(); } |
| |
| const external_string_type external_file_string() const { return Traits::to_external( *this, file_string() ); } |
| const external_string_type external_directory_string() const { return Traits::to_external( *this, directory_string() ); } |
| |
| basic_path root_path() const; |
| string_type root_name() const; |
| string_type root_directory() const; |
| basic_path relative_path() const; |
| basic_path parent_path() const; |
| string_type filename() const; |
| string_type stem() const; |
| string_type extension() const; |
| |
| # ifndef BOOST_FILESYSTEM_NO_DEPRECATED |
| string_type leaf() const { return filename(); } |
| basic_path branch_path() const { return parent_path(); } |
| bool has_leaf() const { return !m_path.empty(); } |
| bool has_branch_path() const { return !parent_path().empty(); } |
| # endif |
| |
| bool empty() const { return m_path.empty(); } // name consistent with std containers |
| bool is_complete() const; |
| bool has_root_path() const; |
| bool has_root_name() const; |
| bool has_root_directory() const; |
| bool has_relative_path() const { return !relative_path().empty(); } |
| bool has_filename() const { return !m_path.empty(); } |
| bool has_parent_path() const { return !parent_path().empty(); } |
| |
| // iterators |
| class iterator : public boost::iterator_facade< |
| iterator, |
| string_type const, |
| boost::bidirectional_traversal_tag > |
| { |
| private: |
| friend class boost::iterator_core_access; |
| friend class boost::BOOST_FILESYSTEM2_NAMESPACE::basic_path<String, Traits>; |
| |
| const string_type & dereference() const |
| { return m_name; } |
| bool equal( const iterator & rhs ) const |
| { return m_path_ptr == rhs.m_path_ptr && m_pos == rhs.m_pos; } |
| |
| friend class boost::BOOST_FILESYSTEM2_NAMESPACE::detail::iterator_helper<path_type>; |
| |
| void increment() |
| { |
| boost::BOOST_FILESYSTEM2_NAMESPACE::detail::iterator_helper<path_type>::do_increment( |
| *this ); |
| } |
| void decrement() |
| { |
| boost::BOOST_FILESYSTEM2_NAMESPACE::detail::iterator_helper<path_type>::do_decrement( |
| *this ); |
| } |
| |
| string_type m_name; // current element |
| const basic_path * m_path_ptr; // path being iterated over |
| typename string_type::size_type m_pos; // position of name in |
| // path_ptr->string(). The |
| // end() iterator is indicated by |
| // pos == path_ptr->m_path.size() |
| }; // iterator |
| |
| typedef iterator const_iterator; |
| |
| iterator begin() const; |
| iterator end() const; |
| |
| private: |
| // Note: This is an implementation for POSIX and Windows, where there |
| // are only minor differences between generic and native path grammars. |
| // Private members might be quite different in other implementations, |
| // particularly where there were wide differences between portable and |
| // native path formats, or between file_string() and |
| // directory_string() formats, or simply that the implementation |
| // was willing expend additional memory to achieve greater speed for |
| // some operations at the expense of other operations. |
| |
| string_type m_path; // invariant: portable path grammar |
| // on Windows, backslashes converted to slashes |
| |
| # ifdef BOOST_CYGWIN_PATH |
| bool m_cygwin_root; // if present, m_path[0] was slash. note: initialization |
| // done by append |
| # endif |
| |
| void m_append_separator_if_needed(); |
| void m_append( value_type value ); // converts Windows alt_separator |
| |
| // Was qualified; como433beta8 reports: |
| // warning #427-D: qualified name is not allowed in member declaration |
| friend class iterator; |
| friend class boost::BOOST_FILESYSTEM2_NAMESPACE::detail::iterator_helper<path_type>; |
| |
| // Deprecated features ease transition for existing code. Don't use these |
| // in new code. |
| # ifndef BOOST_FILESYSTEM_NO_DEPRECATED |
| public: |
| typedef bool (*name_check)( const std::string & name ); |
| basic_path( const string_type & str, name_check ) { operator/=( str ); } |
| basic_path( const typename string_type::value_type * s, name_check ) |
| { operator/=( s );} |
| string_type native_file_string() const { return file_string(); } |
| string_type native_directory_string() const { return directory_string(); } |
| static bool default_name_check_writable() { return false; } |
| static void default_name_check( name_check ) {} |
| static name_check default_name_check() { return 0; } |
| basic_path & canonize(); |
| basic_path & normalize(); |
| # endif |
| }; |
| |
| // basic_path non-member functions ---------------------------------------// |
| |
| template< class String, class Traits > |
| inline void swap( basic_path<String, Traits> & lhs, |
| basic_path<String, Traits> & rhs ) { lhs.swap( rhs ); } |
| |
| template< class String, class Traits > |
| bool operator<( const basic_path<String, Traits> & lhs, const basic_path<String, Traits> & rhs ) |
| { |
| return std::lexicographical_compare( |
| lhs.begin(), lhs.end(), rhs.begin(), rhs.end() ); |
| } |
| |
| template< class String, class Traits > |
| bool operator<( const typename basic_path<String, Traits>::string_type::value_type * lhs, |
| const basic_path<String, Traits> & rhs ) |
| { |
| basic_path<String, Traits> tmp( lhs ); |
| return std::lexicographical_compare( |
| tmp.begin(), tmp.end(), rhs.begin(), rhs.end() ); |
| } |
| |
| template< class String, class Traits > |
| bool operator<( const typename basic_path<String, Traits>::string_type & lhs, |
| const basic_path<String, Traits> & rhs ) |
| { |
| basic_path<String, Traits> tmp( lhs ); |
| return std::lexicographical_compare( |
| tmp.begin(), tmp.end(), rhs.begin(), rhs.end() ); |
| } |
| |
| template< class String, class Traits > |
| bool operator<( const basic_path<String, Traits> & lhs, |
| const typename basic_path<String, Traits>::string_type::value_type * rhs ) |
| { |
| basic_path<String, Traits> tmp( rhs ); |
| return std::lexicographical_compare( |
| lhs.begin(), lhs.end(), tmp.begin(), tmp.end() ); |
| } |
| |
| template< class String, class Traits > |
| bool operator<( const basic_path<String, Traits> & lhs, |
| const typename basic_path<String, Traits>::string_type & rhs ) |
| { |
| basic_path<String, Traits> tmp( rhs ); |
| return std::lexicographical_compare( |
| lhs.begin(), lhs.end(), tmp.begin(), tmp.end() ); |
| } |
| |
| // operator == uses hand-written compare rather than !(lhs < rhs) && !(rhs < lhs) |
| // because the result is the same yet the direct compare is much more efficient |
| // than lexicographical_compare, which would also be called twice. |
| |
| template< class String, class Traits > |
| inline bool operator==( const basic_path<String, Traits> & lhs, |
| const typename basic_path<String, Traits>::string_type::value_type * rhs ) |
| { |
| typedef typename |
| boost::BOOST_FILESYSTEM2_NAMESPACE::basic_path<String, Traits> path_type; |
| const typename path_type::string_type::value_type * l (lhs.string().c_str()); |
| while ( (*l == *rhs |
| # ifdef BOOST_WINDOWS_PATH |
| || (*l == path_alt_separator<path_type>::value && *rhs == slash<path_type>::value) |
| || (*l == slash<path_type>::value && *rhs == path_alt_separator<path_type>::value) |
| # endif |
| ) && *l ) { ++l; ++rhs; } |
| return *l == *rhs |
| # ifdef BOOST_WINDOWS_PATH |
| || (*l == path_alt_separator<path_type>::value && *rhs == slash<path_type>::value) |
| || (*l == slash<path_type>::value && *rhs == path_alt_separator<path_type>::value) |
| # endif |
| ; |
| } |
| |
| template< class String, class Traits > |
| inline bool operator==( const basic_path<String, Traits> & lhs, |
| const basic_path<String, Traits> & rhs ) |
| { |
| return lhs == rhs.string().c_str(); |
| } |
| |
| template< class String, class Traits > |
| inline bool operator==( const typename basic_path<String, Traits>::string_type::value_type * lhs, |
| const basic_path<String, Traits> & rhs ) |
| { |
| return rhs == lhs; |
| } |
| |
| template< class String, class Traits > |
| inline bool operator==( const typename basic_path<String, Traits>::string_type & lhs, |
| const basic_path<String, Traits> & rhs ) |
| { |
| return rhs == lhs.c_str(); |
| } |
| |
| template< class String, class Traits > |
| inline bool operator==( const basic_path<String, Traits> & lhs, |
| const typename basic_path<String, Traits>::string_type & rhs ) |
| { |
| return lhs == rhs.c_str(); |
| } |
| |
| template< class String, class Traits > |
| inline bool operator!=( const basic_path<String, Traits> & lhs, |
| const basic_path<String, Traits> & rhs ) |
| { return !(lhs == rhs); } |
| |
| template< class String, class Traits > |
| inline bool operator!=( const typename basic_path<String, |
| Traits>::string_type::value_type * lhs, |
| const basic_path<String, Traits> & rhs ) |
| { return !(lhs == rhs); } |
| |
| template< class String, class Traits > |
| inline bool operator!=( const typename basic_path<String, Traits>::string_type & lhs, |
| const basic_path<String, Traits> & rhs ) |
| { return !(lhs == rhs); } |
| |
| template< class String, class Traits > |
| inline bool operator!=( const basic_path<String, Traits> & lhs, |
| const typename basic_path<String, Traits>::string_type::value_type * rhs ) |
| { return !(lhs == rhs); } |
| |
| template< class String, class Traits > |
| inline bool operator!=( const basic_path<String, Traits> & lhs, |
| const typename basic_path<String, Traits>::string_type & rhs ) |
| { return !(lhs == rhs); } |
| |
| template< class String, class Traits > |
| inline bool operator>( const basic_path<String, Traits> & lhs, const basic_path<String, Traits> & rhs ) { return rhs < lhs; } |
| |
| template< class String, class Traits > |
| inline bool operator>( const typename basic_path<String, Traits>::string_type::value_type * lhs, |
| const basic_path<String, Traits> & rhs ) { return rhs < basic_path<String, Traits>(lhs); } |
| |
| template< class String, class Traits > |
| inline bool operator>( const typename basic_path<String, Traits>::string_type & lhs, |
| const basic_path<String, Traits> & rhs ) { return rhs < basic_path<String, Traits>(lhs); } |
| |
| template< class String, class Traits > |
| inline bool operator>( const basic_path<String, Traits> & lhs, |
| const typename basic_path<String, Traits>::string_type::value_type * rhs ) |
| { return basic_path<String, Traits>(rhs) < lhs; } |
| |
| template< class String, class Traits > |
| inline bool operator>( const basic_path<String, Traits> & lhs, |
| const typename basic_path<String, Traits>::string_type & rhs ) |
| { return basic_path<String, Traits>(rhs) < lhs; } |
| |
| template< class String, class Traits > |
| inline bool operator<=( const basic_path<String, Traits> & lhs, const basic_path<String, Traits> & rhs ) { return !(rhs < lhs); } |
| |
| template< class String, class Traits > |
| inline bool operator<=( const typename basic_path<String, Traits>::string_type::value_type * lhs, |
| const basic_path<String, Traits> & rhs ) { return !(rhs < basic_path<String, Traits>(lhs)); } |
| |
| template< class String, class Traits > |
| inline bool operator<=( const typename basic_path<String, Traits>::string_type & lhs, |
| const basic_path<String, Traits> & rhs ) { return !(rhs < basic_path<String, Traits>(lhs)); } |
| |
| template< class String, class Traits > |
| inline bool operator<=( const basic_path<String, Traits> & lhs, |
| const typename basic_path<String, Traits>::string_type::value_type * rhs ) |
| { return !(basic_path<String, Traits>(rhs) < lhs); } |
| |
| template< class String, class Traits > |
| inline bool operator<=( const basic_path<String, Traits> & lhs, |
| const typename basic_path<String, Traits>::string_type & rhs ) |
| { return !(basic_path<String, Traits>(rhs) < lhs); } |
| |
| template< class String, class Traits > |
| inline bool operator>=( const basic_path<String, Traits> & lhs, const basic_path<String, Traits> & rhs ) { return !(lhs < rhs); } |
| |
| template< class String, class Traits > |
| inline bool operator>=( const typename basic_path<String, Traits>::string_type::value_type * lhs, |
| const basic_path<String, Traits> & rhs ) { return !(lhs < basic_path<String, Traits>(rhs)); } |
| |
| template< class String, class Traits > |
| inline bool operator>=( const typename basic_path<String, Traits>::string_type & lhs, |
| const basic_path<String, Traits> & rhs ) { return !(lhs < basic_path<String, Traits>(rhs)); } |
| |
| template< class String, class Traits > |
| inline bool operator>=( const basic_path<String, Traits> & lhs, |
| const typename basic_path<String, Traits>::string_type::value_type * rhs ) |
| { return !(basic_path<String, Traits>(lhs) < rhs); } |
| |
| template< class String, class Traits > |
| inline bool operator>=( const basic_path<String, Traits> & lhs, |
| const typename basic_path<String, Traits>::string_type & rhs ) |
| { return !(basic_path<String, Traits>(lhs) < rhs); } |
| |
| // operator / |
| |
| template< class String, class Traits > |
| inline basic_path<String, Traits> operator/( |
| const basic_path<String, Traits> & lhs, |
| const basic_path<String, Traits> & rhs ) |
| { return basic_path<String, Traits>( lhs ) /= rhs; } |
| |
| template< class String, class Traits > |
| inline basic_path<String, Traits> operator/( |
| const basic_path<String, Traits> & lhs, |
| const typename String::value_type * rhs ) |
| { return basic_path<String, Traits>( lhs ) /= |
| basic_path<String, Traits>( rhs ); } |
| |
| template< class String, class Traits > |
| inline basic_path<String, Traits> operator/( |
| const basic_path<String, Traits> & lhs, const String & rhs ) |
| { return basic_path<String, Traits>( lhs ) /= |
| basic_path<String, Traits>( rhs ); } |
| |
| template< class String, class Traits > |
| inline basic_path<String, Traits> operator/( |
| const typename String::value_type * lhs, |
| const basic_path<String, Traits> & rhs ) |
| { return basic_path<String, Traits>( lhs ) /= rhs; } |
| |
| template< class String, class Traits > |
| inline basic_path<String, Traits> operator/( |
| const String & lhs, const basic_path<String, Traits> & rhs ) |
| { return basic_path<String, Traits>( lhs ) /= rhs; } |
| |
| // inserters and extractors --------------------------------------------// |
| |
| // bypass VC++ 7.0 and earlier, and broken Borland compilers |
| # if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) && !BOOST_WORKAROUND(__BORLANDC__, < 0x610) |
| template< class Path > |
| std::basic_ostream< typename Path::string_type::value_type, |
| typename Path::string_type::traits_type > & |
| operator<< |
| ( std::basic_ostream< typename Path::string_type::value_type, |
| typename Path::string_type::traits_type >& os, const Path & ph ) |
| { |
| os << ph.string(); |
| return os; |
| } |
| |
| template< class Path > |
| std::basic_istream< typename Path::string_type::value_type, |
| typename Path::string_type::traits_type > & |
| operator>> |
| ( std::basic_istream< typename Path::string_type::value_type, |
| typename Path::string_type::traits_type >& is, Path & ph ) |
| { |
| typename Path::string_type str; |
| std::getline(is, str); // See ticket 3863 |
| ph = str; |
| return is; |
| } |
| # elif BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) |
| template< class String, class Traits > |
| std::basic_ostream< BOOST_DEDUCED_TYPENAME String::value_type, |
| BOOST_DEDUCED_TYPENAME String::traits_type > & |
| operator<< |
| ( std::basic_ostream< BOOST_DEDUCED_TYPENAME String::value_type, |
| BOOST_DEDUCED_TYPENAME String::traits_type >& os, |
| const basic_path< String, Traits > & ph ) |
| { |
| os << ph.string(); |
| return os; |
| } |
| |
| template< class String, class Traits > |
| std::basic_istream< BOOST_DEDUCED_TYPENAME String::value_type, |
| BOOST_DEDUCED_TYPENAME String::traits_type > & |
| operator>> |
| ( std::basic_istream< BOOST_DEDUCED_TYPENAME String::value_type, |
| BOOST_DEDUCED_TYPENAME String::traits_type> & is, |
| basic_path< String, Traits > & ph ) |
| { |
| String str; |
| std::getline(is, str); // See ticket 3863 |
| ph = str; |
| return is; |
| } |
| # endif |
| |
| // basic_filesystem_error helpers --------------------------------------// |
| |
| // Originally choice of implementation was done via specialization of |
| // basic_filesystem_error::what(). Several compilers (GCC, aCC, etc.) |
| // couldn't handle that, so the choice is now accomplished by overloading. |
| |
| namespace detail |
| { |
| // BOOST_FILESYSTEM_DECL version works for VC++ but not GCC. Go figure! |
| inline |
| const char * what( const char * sys_err_what, |
| const path & path1_arg, const path & path2_arg, std::string & target ) |
| { |
| try |
| { |
| if ( target.empty() ) |
| { |
| target = sys_err_what; |
| if ( !path1_arg.empty() ) |
| { |
| target += ": \""; |
| target += path1_arg.file_string(); |
| target += "\""; |
| } |
| if ( !path2_arg.empty() ) |
| { |
| target += ", \""; |
| target += path2_arg.file_string(); |
| target += "\""; |
| } |
| } |
| return target.c_str(); |
| } |
| catch (...) |
| { |
| return sys_err_what; |
| } |
| } |
| |
| template<class Path> |
| const char * what( const char * sys_err_what, |
| const Path & /*path1_arg*/, const Path & /*path2_arg*/, std::string & /*target*/ ) |
| { |
| return sys_err_what; |
| } |
| } |
| |
| // basic_filesystem_error ----------------------------------------------// |
| |
| template<class Path> |
| class basic_filesystem_error : public system::system_error |
| { |
| // see http://www.boost.org/more/error_handling.html for design rationale |
| public: |
| // compiler generates copy constructor and copy assignment |
| |
| typedef Path path_type; |
| |
| basic_filesystem_error( const std::string & what_arg, |
| system::error_code ec ); |
| |
| basic_filesystem_error( const std::string & what_arg, |
| const path_type & path1_arg, system::error_code ec ); |
| |
| basic_filesystem_error( const std::string & what_arg, const path_type & path1_arg, |
| const path_type & path2_arg, system::error_code ec ); |
| |
| ~basic_filesystem_error() throw() {} |
| |
| const path_type & path1() const |
| { |
| static const path_type empty_path; |
| return m_imp_ptr.get() ? m_imp_ptr->m_path1 : empty_path ; |
| } |
| const path_type & path2() const |
| { |
| static const path_type empty_path; |
| return m_imp_ptr.get() ? m_imp_ptr->m_path2 : empty_path ; |
| } |
| |
| const char * what() const throw() |
| { |
| if ( !m_imp_ptr.get() ) |
| return system::system_error::what(); |
| return detail::what( system::system_error::what(), m_imp_ptr->m_path1, |
| m_imp_ptr->m_path2, m_imp_ptr->m_what ); |
| } |
| |
| private: |
| struct m_imp |
| { |
| path_type m_path1; // may be empty() |
| path_type m_path2; // may be empty() |
| std::string m_what; // not built until needed |
| }; |
| boost::shared_ptr<m_imp> m_imp_ptr; |
| }; |
| |
| typedef basic_filesystem_error<path> filesystem_error; |
| |
| # ifndef BOOST_FILESYSTEM2_NARROW_ONLY |
| typedef basic_filesystem_error<wpath> wfilesystem_error; |
| # endif |
| |
| // path::name_checks -----------------------------------------------------// |
| |
| BOOST_FILESYSTEM_DECL bool portable_posix_name( const std::string & name ); |
| BOOST_FILESYSTEM_DECL bool windows_name( const std::string & name ); |
| BOOST_FILESYSTEM_DECL bool portable_name( const std::string & name ); |
| BOOST_FILESYSTEM_DECL bool portable_directory_name( const std::string & name ); |
| BOOST_FILESYSTEM_DECL bool portable_file_name( const std::string & name ); |
| BOOST_FILESYSTEM_DECL bool native( const std::string & name ); |
| inline bool no_check( const std::string & ) |
| { return true; } |
| |
| // implementation -----------------------------------------------------------// |
| |
| namespace detail |
| { |
| |
| // is_separator helper ------------------------------------------------// |
| |
| template<class Path> |
| inline bool is_separator( typename Path::string_type::value_type c ) |
| { |
| return c == slash<Path>::value |
| # ifdef BOOST_WINDOWS_PATH |
| || c == path_alt_separator<Path>::value |
| # endif |
| ; |
| } |
| |
| // filename_pos helper ----------------------------------------------------// |
| |
| template<class String, class Traits> |
| typename String::size_type filename_pos( |
| const String & str, // precondition: portable generic path grammar |
| typename String::size_type end_pos ) // end_pos is past-the-end position |
| // return 0 if str itself is filename (or empty) |
| { |
| typedef typename |
| boost::BOOST_FILESYSTEM2_NAMESPACE::basic_path<String, Traits> path_type; |
| |
| // case: "//" |
| if ( end_pos == 2 |
| && str[0] == slash<path_type>::value |
| && str[1] == slash<path_type>::value ) return 0; |
| |
| // case: ends in "/" |
| if ( end_pos && str[end_pos-1] == slash<path_type>::value ) |
| return end_pos-1; |
| |
| // set pos to start of last element |
| typename String::size_type pos( |
| str.find_last_of( slash<path_type>::value, end_pos-1 ) ); |
| # ifdef BOOST_WINDOWS_PATH |
| if ( pos == String::npos ) |
| pos = str.find_last_of( path_alt_separator<path_type>::value, end_pos-1 ); |
| if ( pos == String::npos ) |
| pos = str.find_last_of( colon<path_type>::value, end_pos-2 ); |
| # endif |
| |
| return ( pos == String::npos // path itself must be a filename (or empty) |
| || (pos == 1 && str[0] == slash<path_type>::value) ) // or net |
| ? 0 // so filename is entire string |
| : pos + 1; // or starts after delimiter |
| } |
| |
| // first_element helper -----------------------------------------------// |
| // sets pos and len of first element, excluding extra separators |
| // if src.empty(), sets pos,len, to 0,0. |
| |
| template<class String, class Traits> |
| void first_element( |
| const String & src, // precondition: portable generic path grammar |
| typename String::size_type & element_pos, |
| typename String::size_type & element_size, |
| # if !BOOST_WORKAROUND( BOOST_MSVC, <= 1310 ) // VC++ 7.1 |
| typename String::size_type size = String::npos |
| # else |
| typename String::size_type size = -1 |
| # endif |
| ) |
| { |
| if ( size == String::npos ) size = src.size(); |
| element_pos = 0; |
| element_size = 0; |
| if ( src.empty() ) return; |
| |
| typedef typename boost::BOOST_FILESYSTEM2_NAMESPACE::basic_path<String, Traits> path_type; |
| |
| typename String::size_type cur(0); |
| |
| // deal with // [network] |
| if ( size >= 2 && src[0] == slash<path_type>::value |
| && src[1] == slash<path_type>::value |
| && (size == 2 |
| || src[2] != slash<path_type>::value) ) |
| { |
| cur += 2; |
| element_size += 2; |
| } |
| |
| // leading (not non-network) separator |
| else if ( src[0] == slash<path_type>::value ) |
| { |
| ++element_size; |
| // bypass extra leading separators |
| while ( cur+1 < size |
| && src[cur+1] == slash<path_type>::value ) |
| { |
| ++cur; |
| ++element_pos; |
| } |
| return; |
| } |
| |
| // at this point, we have either a plain name, a network name, |
| // or (on Windows only) a device name |
| |
| // find the end |
| while ( cur < size |
| # ifdef BOOST_WINDOWS_PATH |
| && src[cur] != colon<path_type>::value |
| # endif |
| && src[cur] != slash<path_type>::value ) |
| { |
| ++cur; |
| ++element_size; |
| } |
| |
| # ifdef BOOST_WINDOWS_PATH |
| if ( cur == size ) return; |
| // include device delimiter |
| if ( src[cur] == colon<path_type>::value ) |
| { ++element_size; } |
| # endif |
| |
| return; |
| } |
| |
| // root_directory_start helper ----------------------------------------// |
| |
| template<class String, class Traits> |
| typename String::size_type root_directory_start( |
| const String & s, // precondition: portable generic path grammar |
| typename String::size_type size ) |
| // return npos if no root_directory found |
| { |
| typedef typename boost::BOOST_FILESYSTEM2_NAMESPACE::basic_path<String, Traits> path_type; |
| |
| # ifdef BOOST_WINDOWS_PATH |
| // case "c:/" |
| if ( size > 2 |
| && s[1] == colon<path_type>::value |
| && s[2] == slash<path_type>::value ) return 2; |
| # endif |
| |
| // case "//" |
| if ( size == 2 |
| && s[0] == slash<path_type>::value |
| && s[1] == slash<path_type>::value ) return String::npos; |
| |
| // case "//net {/}" |
| if ( size > 3 |
| && s[0] == slash<path_type>::value |
| && s[1] == slash<path_type>::value |
| && s[2] != slash<path_type>::value ) |
| { |
| typename String::size_type pos( |
| s.find( slash<path_type>::value, 2 ) ); |
| return pos < size ? pos : String::npos; |
| } |
| |
| // case "/" |
| if ( size > 0 && s[0] == slash<path_type>::value ) return 0; |
| |
| return String::npos; |
| } |
| |
| // is_non_root_slash helper -------------------------------------------// |
| |
| template<class String, class Traits> |
| bool is_non_root_slash( const String & str, |
| typename String::size_type pos ) // pos is position of the slash |
| { |
| typedef typename |
| boost::BOOST_FILESYSTEM2_NAMESPACE::basic_path<String, Traits> |
| path_type; |
| |
| assert( !str.empty() && str[pos] == slash<path_type>::value |
| && "precondition violation" ); |
| |
| // subsequent logic expects pos to be for leftmost slash of a set |
| while ( pos > 0 && str[pos-1] == slash<path_type>::value ) |
| --pos; |
| |
| return pos != 0 |
| && (pos <= 2 || str[1] != slash<path_type>::value |
| || str.find( slash<path_type>::value, 2 ) != pos) |
| # ifdef BOOST_WINDOWS_PATH |
| && (pos !=2 || str[1] != colon<path_type>::value) |
| # endif |
| ; |
| } |
| } // namespace detail |
| |
| // decomposition functions ----------------------------------------------// |
| |
| template<class String, class Traits> |
| String basic_path<String, Traits>::filename() const |
| { |
| typename String::size_type end_pos( |
| detail::filename_pos<String, Traits>( m_path, m_path.size() ) ); |
| return (m_path.size() |
| && end_pos |
| && m_path[end_pos] == slash<path_type>::value |
| && detail::is_non_root_slash< String, Traits >(m_path, end_pos)) |
| ? String( 1, dot<path_type>::value ) |
| : m_path.substr( end_pos ); |
| } |
| |
| template<class String, class Traits> |
| String basic_path<String, Traits>::stem() const |
| { |
| string_type name = filename(); |
| typename string_type::size_type n = name.rfind(dot<path_type>::value); |
| return name.substr(0, n); |
| } |
| |
| template<class String, class Traits> |
| String basic_path<String, Traits>::extension() const |
| { |
| string_type name = filename(); |
| typename string_type::size_type n = name.rfind(dot<path_type>::value); |
| if (n != string_type::npos) |
| return name.substr(n); |
| else |
| return string_type(); |
| } |
| |
| template<class String, class Traits> |
| basic_path<String, Traits> basic_path<String, Traits>::parent_path() const |
| { |
| typename String::size_type end_pos( |
| detail::filename_pos<String, Traits>( m_path, m_path.size() ) ); |
| |
| bool filename_was_separator( m_path.size() |
| && m_path[end_pos] == slash<path_type>::value ); |
| |
| // skip separators unless root directory |
| typename string_type::size_type root_dir_pos( detail::root_directory_start |
| <string_type, traits_type>( m_path, end_pos ) ); |
| for ( ; |
| end_pos > 0 |
| && (end_pos-1) != root_dir_pos |
| && m_path[end_pos-1] == slash<path_type>::value |
| ; |
| --end_pos ) {} |
| |
| return (end_pos == 1 && root_dir_pos == 0 && filename_was_separator) |
| ? path_type() |
| : path_type( m_path.substr( 0, end_pos ) ); |
| } |
| |
| template<class String, class Traits> |
| basic_path<String, Traits> basic_path<String, Traits>::relative_path() const |
| { |
| iterator itr( begin() ); |
| for ( ; itr.m_pos != m_path.size() |
| && (itr.m_name[0] == slash<path_type>::value |
| # ifdef BOOST_WINDOWS_PATH |
| || itr.m_name[itr.m_name.size()-1] |
| == colon<path_type>::value |
| # endif |
| ); ++itr ) {} |
| |
| return basic_path<String, Traits>( m_path.substr( itr.m_pos ) ); |
| } |
| |
| template<class String, class Traits> |
| String basic_path<String, Traits>::root_name() const |
| { |
| iterator itr( begin() ); |
| |
| return ( itr.m_pos != m_path.size() |
| && ( |
| ( itr.m_name.size() > 1 |
| && itr.m_name[0] == slash<path_type>::value |
| && itr.m_name[1] == slash<path_type>::value |
| ) |
| # ifdef BOOST_WINDOWS_PATH |
| || itr.m_name[itr.m_name.size()-1] |
| == colon<path_type>::value |
| # endif |
| ) ) |
| ? *itr |
| : String(); |
| } |
| |
| template<class String, class Traits> |
| String basic_path<String, Traits>::root_directory() const |
| { |
| typename string_type::size_type start( |
| detail::root_directory_start<String, Traits>( m_path, m_path.size() ) ); |
| |
| return start == string_type::npos |
| ? string_type() |
| : m_path.substr( start, 1 ); |
| } |
| |
| template<class String, class Traits> |
| basic_path<String, Traits> basic_path<String, Traits>::root_path() const |
| { |
| // even on POSIX, root_name() is non-empty() on network paths |
| return basic_path<String, Traits>( root_name() ) /= root_directory(); |
| } |
| |
| // path query functions -------------------------------------------------// |
| |
| template<class String, class Traits> |
| inline bool basic_path<String, Traits>::is_complete() const |
| { |
| # ifdef BOOST_WINDOWS_PATH |
| return has_root_name() && has_root_directory(); |
| # else |
| return has_root_directory(); |
| # endif |
| } |
| |
| template<class String, class Traits> |
| inline bool basic_path<String, Traits>::has_root_path() const |
| { |
| return !root_path().empty(); |
| } |
| |
| template<class String, class Traits> |
| inline bool basic_path<String, Traits>::has_root_name() const |
| { |
| return !root_name().empty(); |
| } |
| |
| template<class String, class Traits> |
| inline bool basic_path<String, Traits>::has_root_directory() const |
| { |
| return !root_directory().empty(); |
| } |
| |
| // append ---------------------------------------------------------------// |
| |
| template<class String, class Traits> |
| void basic_path<String, Traits>::m_append_separator_if_needed() |
| // requires: !empty() |
| { |
| if ( |
| # ifdef BOOST_WINDOWS_PATH |
| *(m_path.end()-1) != colon<path_type>::value && |
| # endif |
| *(m_path.end()-1) != slash<path_type>::value ) |
| { |
| m_path += slash<path_type>::value; |
| } |
| } |
| |
| template<class String, class Traits> |
| void basic_path<String, Traits>::m_append( value_type value ) |
| { |
| # ifdef BOOST_CYGWIN_PATH |
| if ( m_path.empty() ) m_cygwin_root = (value == slash<path_type>::value); |
| # endif |
| |
| # ifdef BOOST_WINDOWS_PATH |
| // for BOOST_WINDOWS_PATH, convert alt_separator ('\') to separator ('/') |
| m_path += ( value == path_alt_separator<path_type>::value |
| ? slash<path_type>::value |
| : value ); |
| # else |
| m_path += value; |
| # endif |
| } |
| |
| // except that it wouldn't work for BOOST_NO_MEMBER_TEMPLATES compilers, |
| // the append() member template could replace this code. |
| template<class String, class Traits> |
| basic_path<String, Traits> & basic_path<String, Traits>::operator /= |
| ( const value_type * next_p ) |
| { |
| // ignore escape sequence on POSIX or Windows |
| if ( *next_p == slash<path_type>::value |
| && *(next_p+1) == slash<path_type>::value |
| && *(next_p+2) == colon<path_type>::value ) next_p += 3; |
| |
| // append slash<path_type>::value if needed |
| if ( !empty() && *next_p != 0 |
| && !detail::is_separator<path_type>( *next_p ) ) |
| { m_append_separator_if_needed(); } |
| |
| for ( ; *next_p != 0; ++next_p ) m_append( *next_p ); |
| return *this; |
| } |
| |
| # ifndef BOOST_NO_MEMBER_TEMPLATES |
| template<class String, class Traits> template <class InputIterator> |
| basic_path<String, Traits> & basic_path<String, Traits>::append( |
| InputIterator first, InputIterator last ) |
| { |
| // append slash<path_type>::value if needed |
| if ( !empty() && first != last |
| && !detail::is_separator<path_type>( *first ) ) |
| { m_append_separator_if_needed(); } |
| |
| // song-and-dance to avoid violating InputIterator requirements |
| // (which prohibit lookahead) in detecting a possible escape sequence |
| // (escape sequences are simply ignored on POSIX and Windows) |
| bool was_escape_sequence(true); |
| std::size_t append_count(0); |
| typename String::size_type initial_pos( m_path.size() ); |
| |
| for ( ; first != last && *first; ++first ) |
| { |
| if ( append_count == 0 && *first != slash<path_type>::value ) |
| was_escape_sequence = false; |
| if ( append_count == 1 && *first != slash<path_type>::value ) |
| was_escape_sequence = false; |
| if ( append_count == 2 && *first != colon<path_type>::value ) |
| was_escape_sequence = false; |
| m_append( *first ); |
| ++append_count; |
| } |
| |
| // erase escape sequence if any |
| if ( was_escape_sequence && append_count >= 3 ) |
| m_path.erase( initial_pos, 3 ); |
| |
| return *this; |
| } |
| # endif |
| |
| # ifndef BOOST_FILESYSTEM_NO_DEPRECATED |
| |
| // canonize ------------------------------------------------------------// |
| |
| template<class String, class Traits> |
| basic_path<String, Traits> & basic_path<String, Traits>::canonize() |
| { |
| static const typename string_type::value_type dot_str[] |
| = { dot<path_type>::value, 0 }; |
| |
| if ( m_path.empty() ) return *this; |
| |
| path_type temp; |
| |
| for ( iterator itr( begin() ); itr != end(); ++itr ) |
| { |
| temp /= *itr; |
| }; |
| |
| if ( temp.empty() ) temp /= dot_str; |
| m_path = temp.m_path; |
| return *this; |
| } |
| |
| // normalize ------------------------------------------------------------// |
| |
| template<class String, class Traits> |
| basic_path<String, Traits> & basic_path<String, Traits>::normalize() |
| { |
| static const typename string_type::value_type dot_str[] |
| = { dot<path_type>::value, 0 }; |
| |
| if ( m_path.empty() ) return *this; |
| |
| path_type temp; |
| iterator start( begin() ); |
| iterator last( end() ); |
| iterator stop( last-- ); |
| for ( iterator itr( start ); itr != stop; ++itr ) |
| { |
| // ignore "." except at start and last |
| if ( itr->size() == 1 |
| && (*itr)[0] == dot<path_type>::value |
| && itr != start |
| && itr != last ) continue; |
| |
| // ignore a name and following ".." |
| if ( !temp.empty() |
| && itr->size() == 2 |
| && (*itr)[0] == dot<path_type>::value |
| && (*itr)[1] == dot<path_type>::value ) // dot dot |
| { |
| string_type lf( temp.filename() ); |
| if ( lf.size() > 0 |
| && (lf.size() != 1 |
| || (lf[0] != dot<path_type>::value |
| && lf[0] != slash<path_type>::value)) |
| && (lf.size() != 2 |
| || (lf[0] != dot<path_type>::value |
| && lf[1] != dot<path_type>::value |
| # ifdef BOOST_WINDOWS_PATH |
| && lf[1] != colon<path_type>::value |
| # endif |
| ) |
| ) |
| ) |
| { |
| temp.remove_filename(); |
| // if not root directory, must also remove "/" if any |
| if ( temp.m_path.size() > 0 |
| && temp.m_path[temp.m_path.size()-1] |
| == slash<path_type>::value ) |
| { |
| typename string_type::size_type rds( |
| detail::root_directory_start<String,Traits>( temp.m_path, |
| temp.m_path.size() ) ); |
| if ( rds == string_type::npos |
| || rds != temp.m_path.size()-1 ) |
| { temp.m_path.erase( temp.m_path.size()-1 ); } |
| } |
| |
| iterator next( itr ); |
| if ( temp.empty() && ++next != stop |
| && next == last && *last == dot_str ) temp /= dot_str; |
| continue; |
| } |
| } |
| |
| temp /= *itr; |
| }; |
| |
| if ( temp.empty() ) temp /= dot_str; |
| m_path = temp.m_path; |
| return *this; |
| } |
| |
| # endif |
| |
| // modifiers ------------------------------------------------------------// |
| |
| template<class String, class Traits> |
| basic_path<String, Traits> & basic_path<String, Traits>::remove_filename() |
| { |
| m_path.erase( |
| detail::filename_pos<String, Traits>( m_path, m_path.size() ) ); |
| return *this; |
| } |
| |
| template<class String, class Traits> |
| basic_path<String, Traits> & |
| basic_path<String, Traits>::replace_extension( const string_type & new_ext ) |
| { |
| // erase existing extension if any |
| string_type old_ext = extension(); |
| if ( !old_ext.empty() ) |
| m_path.erase( m_path.size() - old_ext.size() ); |
| |
| if ( !new_ext.empty() && new_ext[0] != dot<path_type>::value ) |
| m_path += dot<path_type>::value; |
| |
| m_path += new_ext; |
| |
| return *this; |
| } |
| |
| |
| // path conversion functions --------------------------------------------// |
| |
| template<class String, class Traits> |
| const String |
| basic_path<String, Traits>::file_string() const |
| { |
| # ifdef BOOST_WINDOWS_PATH |
| // for Windows, use the alternate separator, and bypass extra |
| // root separators |
| |
| typename string_type::size_type root_dir_start( |
| detail::root_directory_start<String, Traits>( m_path, m_path.size() ) ); |
| bool in_root( root_dir_start != string_type::npos ); |
| String s; |
| for ( typename string_type::size_type pos( 0 ); |
| pos != m_path.size(); ++pos ) |
| { |
| // special case // [net] |
| if ( pos == 0 && m_path.size() > 1 |
| && m_path[0] == slash<path_type>::value |
| && m_path[1] == slash<path_type>::value |
| && ( m_path.size() == 2 |
| || !detail::is_separator<path_type>( m_path[2] ) |
| ) ) |
| { |
| ++pos; |
| s += path_alt_separator<path_type>::value; |
| s += path_alt_separator<path_type>::value; |
| continue; |
| } |
| |
| // bypass extra root separators |
| if ( in_root ) |
| { |
| if ( s.size() > 0 |
| && s[s.size()-1] == path_alt_separator<path_type>::value |
| && m_path[pos] == slash<path_type>::value |
| ) continue; |
| } |
| |
| if ( m_path[pos] == slash<path_type>::value ) |
| s += path_alt_separator<path_type>::value; |
| else |
| s += m_path[pos]; |
| |
| if ( pos > root_dir_start |
| && m_path[pos] == slash<path_type>::value ) |
| { in_root = false; } |
| } |
| # ifdef BOOST_CYGWIN_PATH |
| if ( m_cygwin_root ) s[0] = slash<path_type>::value; |
| # endif |
| return s; |
| # else |
| return m_path; |
| # endif |
| } |
| |
| // iterator functions ---------------------------------------------------// |
| |
| template<class String, class Traits> |
| typename basic_path<String, Traits>::iterator basic_path<String, Traits>::begin() const |
| { |
| iterator itr; |
| itr.m_path_ptr = this; |
| typename string_type::size_type element_size; |
| detail::first_element<String, Traits>( m_path, itr.m_pos, element_size ); |
| itr.m_name = m_path.substr( itr.m_pos, element_size ); |
| return itr; |
| } |
| |
| template<class String, class Traits> |
| typename basic_path<String, Traits>::iterator basic_path<String, Traits>::end() const |
| { |
| iterator itr; |
| itr.m_path_ptr = this; |
| itr.m_pos = m_path.size(); |
| return itr; |
| } |
| |
| namespace detail |
| { |
| // do_increment ------------------------------------------------------// |
| |
| template<class Path> |
| void iterator_helper<Path>::do_increment( iterator & itr ) |
| { |
| typedef typename Path::string_type string_type; |
| typedef typename Path::traits_type traits_type; |
| |
| assert( itr.m_pos < itr.m_path_ptr->m_path.size() && "basic_path::iterator increment past end()" ); |
| |
| bool was_net( itr.m_name.size() > 2 |
| && itr.m_name[0] == slash<Path>::value |
| && itr.m_name[1] == slash<Path>::value |
| && itr.m_name[2] != slash<Path>::value ); |
| |
| // increment to position past current element |
| itr.m_pos += itr.m_name.size(); |
| |
| // if end reached, create end iterator |
| if ( itr.m_pos == itr.m_path_ptr->m_path.size() ) |
| { |
| itr.m_name.erase( itr.m_name.begin(), itr.m_name.end() ); // VC++ 6.0 lib didn't supply clear() |
| return; |
| } |
| |
| // process separator (Windows drive spec is only case not a separator) |
| if ( itr.m_path_ptr->m_path[itr.m_pos] == slash<Path>::value ) |
| { |
| // detect root directory |
| if ( was_net |
| # ifdef BOOST_WINDOWS_PATH |
| // case "c:/" |
| || itr.m_name[itr.m_name.size()-1] == colon<Path>::value |
| # endif |
| ) |
| { |
| itr.m_name = slash<Path>::value; |
| return; |
| } |
| |
| // bypass separators |
| while ( itr.m_pos != itr.m_path_ptr->m_path.size() |
| && itr.m_path_ptr->m_path[itr.m_pos] == slash<Path>::value ) |
| { ++itr.m_pos; } |
| |
| // detect trailing separator, and treat it as ".", per POSIX spec |
| if ( itr.m_pos == itr.m_path_ptr->m_path.size() |
| && detail::is_non_root_slash< string_type, traits_type >( |
| itr.m_path_ptr->m_path, itr.m_pos-1 ) ) |
| { |
| --itr.m_pos; |
| itr.m_name = dot<Path>::value; |
| return; |
| } |
| } |
| |
| // get next element |
| typename string_type::size_type end_pos( |
| itr.m_path_ptr->m_path.find( slash<Path>::value, itr.m_pos ) ); |
| itr.m_name = itr.m_path_ptr->m_path.substr( itr.m_pos, end_pos - itr.m_pos ); |
| } |
| |
| // do_decrement ------------------------------------------------------// |
| |
| template<class Path> |
| void iterator_helper<Path>::do_decrement( iterator & itr ) |
| { |
| assert( itr.m_pos && "basic_path::iterator decrement past begin()" ); |
| |
| typedef typename Path::string_type string_type; |
| typedef typename Path::traits_type traits_type; |
| |
| typename string_type::size_type end_pos( itr.m_pos ); |
| |
| typename string_type::size_type root_dir_pos( |
| detail::root_directory_start<string_type, traits_type>( |
| itr.m_path_ptr->m_path, end_pos ) ); |
| |
| // if at end and there was a trailing non-root '/', return "." |
| if ( itr.m_pos == itr.m_path_ptr->m_path.size() |
| && itr.m_path_ptr->m_path.size() > 1 |
| && itr.m_path_ptr->m_path[itr.m_pos-1] == slash<Path>::value |
| && detail::is_non_root_slash< string_type, traits_type >( |
| itr.m_path_ptr->m_path, itr.m_pos-1 ) |
| ) |
| { |
| --itr.m_pos; |
| itr.m_name = dot<Path>::value; |
| return; |
| } |
| |
| // skip separators unless root directory |
| for ( |
| ; |
| end_pos > 0 |
| && (end_pos-1) != root_dir_pos |
| && itr.m_path_ptr->m_path[end_pos-1] == slash<Path>::value |
| ; |
| --end_pos ) {} |
| |
| itr.m_pos = detail::filename_pos<string_type, traits_type> |
| ( itr.m_path_ptr->m_path, end_pos ); |
| itr.m_name = itr.m_path_ptr->m_path.substr( itr.m_pos, end_pos - itr.m_pos ); |
| } |
| } // namespace detail |
| |
| // basic_filesystem_error implementation --------------------------------// |
| |
| template<class Path> |
| basic_filesystem_error<Path>::basic_filesystem_error( |
| const std::string & what_arg, system::error_code ec ) |
| : system::system_error(ec, what_arg) |
| { |
| try |
| { |
| m_imp_ptr.reset( new m_imp ); |
| } |
| catch (...) { m_imp_ptr.reset(); } |
| } |
| |
| template<class Path> |
| basic_filesystem_error<Path>::basic_filesystem_error( |
| const std::string & what_arg, const path_type & path1_arg, |
| system::error_code ec ) |
| : system::system_error(ec, what_arg) |
| { |
| try |
| { |
| m_imp_ptr.reset( new m_imp ); |
| m_imp_ptr->m_path1 = path1_arg; |
| } |
| catch (...) { m_imp_ptr.reset(); } |
| } |
| |
| template<class Path> |
| basic_filesystem_error<Path>::basic_filesystem_error( |
| const std::string & what_arg, const path_type & path1_arg, |
| const path_type & path2_arg, system::error_code ec ) |
| : system::system_error(ec, what_arg) |
| { |
| try |
| { |
| m_imp_ptr.reset( new m_imp ); |
| m_imp_ptr->m_path1 = path1_arg; |
| m_imp_ptr->m_path2 = path2_arg; |
| } |
| catch (...) { m_imp_ptr.reset(); } |
| } |
| |
| } // namespace BOOST_FILESYSTEM2_NAMESPACE |
| } // namespace boost |
| |
| //----------------------------------------------------------------------------// |
| |
| namespace boost |
| { |
| namespace filesystem |
| { |
| using filesystem2::basic_path; |
| using filesystem2::path_traits; |
| |
| using filesystem2::slash; |
| using filesystem2::dot; |
| using filesystem2::colon; |
| |
| using filesystem2::path; |
| # ifndef BOOST_FILESYSTEM2_NARROW_ONLY |
| using filesystem2::wpath_traits; |
| using filesystem2::wpath; |
| using filesystem2::wfilesystem_error; |
| # endif |
| using filesystem2::basic_filesystem_error; |
| using filesystem2::filesystem_error; |
| using filesystem2::portable_posix_name; |
| using filesystem2::windows_name; |
| using filesystem2::portable_name; |
| using filesystem2::portable_directory_name; |
| using filesystem2::portable_file_name; |
| using filesystem2::native; |
| using filesystem2::no_check; |
| using filesystem2::swap; |
| using filesystem2::operator<; |
| using filesystem2::operator==; |
| using filesystem2::operator!=; |
| using filesystem2::operator>; |
| using filesystem2::operator<=; |
| using filesystem2::operator>=; |
| using filesystem2::operator/; |
| using filesystem2::operator<<; |
| using filesystem2::operator>>; |
| } |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| #include <boost/config/abi_suffix.hpp> // pops abi_prefix.hpp pragmas |
| |
| #endif // BOOST_FILESYSTEM2_PATH_HPP |