Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

This is the documentation for an old version of Boost. Click here to view this page for the latest version.

boost/filesystem/path.hpp

//  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_FILESYSTEM_PATH_HPP
#define BOOST_FILESYSTEM_PATH_HPP

#include <boost/filesystem/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_FILESYSTEM_NARROW_ONLY
#   include <locale>
# endif

#include <boost/config/abi_prefix.hpp> // must be the last #include

//----------------------------------------------------------------------------//

namespace boost
{
  namespace BOOST_FILESYSTEM_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_FILESYSTEM_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_FILESYSTEM_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_FILESYSTEM_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_FILESYSTEM_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_FILESYSTEM_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 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_FILESYSTEM_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_FILESYSTEM_NAMESPACE::detail::iterator_helper<path_type>;

        void increment()
        { 
          boost::BOOST_FILESYSTEM_NAMESPACE::detail::iterator_helper<path_type>::do_increment(
            *this );
        }
        void decrement()
        { 
          boost::BOOST_FILESYSTEM_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_FILESYSTEM_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 string compare rather than !(lhs < rhs) && !(rhs < lhs) because
    //  the result is the same yet the direct string compare is much more efficient that
    //  lexicographical_compare, and lexicographical_compare used twice at that.

    template< class String, class Traits >
    inline bool operator==( const basic_path<String, Traits> & lhs, const basic_path<String, Traits> & rhs )
    { 
      return lhs.string() == rhs.string();
    }

    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.string();
    }

    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.string();
    }

    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.string() == 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.string() == rhs;
    }

    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;
      is >> str;
      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;
      is >> str;
      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_FILESYSTEM_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_FILESYSTEM_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_FILESYSTEM_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_FILESYSTEM_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_FILESYSTEM_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('.');
      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('.');
      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_FILESYSTEM_NAMESPACE
} // namespace boost

#include <boost/config/abi_suffix.hpp> // pops abi_prefix.hpp pragmas

#endif // BOOST_FILESYSTEM_PATH_HPP