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