imgtools/imglib/boostlibrary/boost/filesystem/path.hpp
changeset 607 378360dbbdba
parent 600 6d08f4a05d93
equal deleted inserted replaced
591:22486c9c7b15 607:378360dbbdba
       
     1 //  boost/filesystem/path.hpp  -----------------------------------------------//
       
     2 
       
     3 //  Copyright Beman Dawes 2002-2005
       
     4 //  Copyright Vladimir Prus 2002
       
     5 
       
     6 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
       
     7 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       
     8 
       
     9 //  See library home page at http://www.boost.org/libs/filesystem
       
    10 
       
    11 //  basic_path's stem(), extension(), and replace_extension() are based on
       
    12 //  basename(), extension(), and change_extension() from the original
       
    13 //  filesystem/convenience.hpp header by Vladimir Prus.
       
    14 
       
    15 //----------------------------------------------------------------------------// 
       
    16 
       
    17 #ifndef BOOST_FILESYSTEM_PATH_HPP
       
    18 #define BOOST_FILESYSTEM_PATH_HPP
       
    19 
       
    20 #include <boost/filesystem/config.hpp>
       
    21 #include <boost/system/system_error.hpp>
       
    22 #include <boost/iterator/iterator_facade.hpp>
       
    23 #include <boost/throw_exception.hpp>
       
    24 #include <boost/shared_ptr.hpp>
       
    25 #include <boost/type_traits/is_same.hpp>
       
    26 #include <boost/static_assert.hpp>
       
    27 
       
    28 #include <string>
       
    29 #include <algorithm> // for lexicographical_compare
       
    30 #include <iosfwd>    // needed by basic_path inserter and extractor
       
    31 #include <stdexcept>
       
    32 #include <cassert>
       
    33 
       
    34 # ifndef BOOST_FILESYSTEM_NARROW_ONLY
       
    35 #   include <locale>
       
    36 # endif
       
    37 
       
    38 #include <boost/config/abi_prefix.hpp> // must be the last #include
       
    39 
       
    40 //----------------------------------------------------------------------------//
       
    41 
       
    42 namespace boost
       
    43 {
       
    44   namespace BOOST_FILESYSTEM_NAMESPACE
       
    45   {
       
    46     template<class String, class Traits> class basic_path;
       
    47 
       
    48     struct path_traits;
       
    49     typedef basic_path< std::string, path_traits > path;
       
    50 
       
    51     struct path_traits
       
    52     {
       
    53       typedef std::string internal_string_type;
       
    54       typedef std::string external_string_type;
       
    55       static external_string_type to_external( const path &,
       
    56         const internal_string_type & src ) { return src; }
       
    57       static internal_string_type to_internal(
       
    58         const external_string_type & src ) { return src; }
       
    59     };
       
    60 
       
    61 # ifndef BOOST_FILESYSTEM_NARROW_ONLY
       
    62 
       
    63     struct BOOST_FILESYSTEM_DECL wpath_traits;
       
    64     
       
    65     typedef basic_path< std::wstring, wpath_traits > wpath;
       
    66 
       
    67     struct BOOST_FILESYSTEM_DECL wpath_traits
       
    68     {
       
    69       typedef std::wstring internal_string_type;
       
    70 # ifdef BOOST_WINDOWS_API
       
    71       typedef std::wstring external_string_type;
       
    72       static external_string_type to_external( const wpath &,
       
    73         const internal_string_type & src ) { return src; }
       
    74       static internal_string_type to_internal(
       
    75         const external_string_type & src ) { return src; }
       
    76 # else
       
    77       typedef std::string external_string_type;
       
    78       static external_string_type to_external( const wpath & ph,
       
    79         const internal_string_type & src );
       
    80       static internal_string_type to_internal(
       
    81         const external_string_type & src );
       
    82 # endif
       
    83       static void imbue( const std::locale & loc );
       
    84       static bool imbue( const std::locale & loc, const std::nothrow_t & );
       
    85     };
       
    86 
       
    87 # endif // ifndef BOOST_FILESYSTEM_NARROW_ONLY
       
    88 
       
    89     //  path traits  ---------------------------------------------------------//
       
    90 
       
    91     template<class Path> struct is_basic_path
       
    92       { BOOST_STATIC_CONSTANT( bool, value = false ); };
       
    93     template<> struct is_basic_path<path>
       
    94       { BOOST_STATIC_CONSTANT( bool, value = true ); };
       
    95 # ifndef BOOST_FILESYSTEM_NARROW_ONLY
       
    96     template<> struct is_basic_path<wpath>
       
    97       { BOOST_STATIC_CONSTANT( bool, value = true ); };
       
    98 # endif
       
    99 
       
   100     // These only have to be specialized if Path::string_type::value_type
       
   101     // is not convertible from char, although specializations may eliminate
       
   102     // compiler warnings. See ticket 2543.
       
   103     template<class Path> struct slash
       
   104       { BOOST_STATIC_CONSTANT( char, value = '/' ); };
       
   105 
       
   106     template<class Path> struct dot
       
   107       { BOOST_STATIC_CONSTANT( char, value = '.' ); };
       
   108 
       
   109     template<class Path> struct colon
       
   110       { BOOST_STATIC_CONSTANT( char, value = ':' ); };
       
   111 
       
   112 # ifndef BOOST_FILESYSTEM_NARROW_ONLY
       
   113     template<> struct slash<wpath>
       
   114       { BOOST_STATIC_CONSTANT( wchar_t, value = L'/' ); };
       
   115     template<> struct dot<wpath>
       
   116       { BOOST_STATIC_CONSTANT( wchar_t, value = L'.' ); };
       
   117     template<> struct colon<wpath>
       
   118       { BOOST_STATIC_CONSTANT( wchar_t, value = L':' ); };
       
   119 # endif
       
   120 
       
   121 # ifdef BOOST_WINDOWS_PATH
       
   122     template<class Path> struct path_alt_separator
       
   123       { BOOST_STATIC_CONSTANT( char, value = '\\' ); };
       
   124 #   ifndef BOOST_FILESYSTEM_NARROW_ONLY
       
   125     template<> struct path_alt_separator<wpath>
       
   126       { BOOST_STATIC_CONSTANT( wchar_t, value = L'\\' ); };
       
   127 #   endif
       
   128 # endif
       
   129 
       
   130     //  workaround for VC++ 7.0 and earlier issues with nested classes
       
   131     namespace detail
       
   132     {
       
   133       template<class Path>
       
   134       class iterator_helper
       
   135       {
       
   136       public:
       
   137         typedef typename Path::iterator iterator;
       
   138         static void do_increment( iterator & ph );
       
   139         static void do_decrement( iterator & ph );
       
   140       };
       
   141     }
       
   142 
       
   143     //  basic_path  ----------------------------------------------------------//
       
   144   
       
   145     template<class String, class Traits>
       
   146     class basic_path
       
   147     {
       
   148     // invariant: m_path valid according to the portable generic path grammar
       
   149 
       
   150       // validate template arguments
       
   151 // TODO: get these working
       
   152 //      BOOST_STATIC_ASSERT( ::boost::is_same<String,typename Traits::internal_string_type>::value );
       
   153 //      BOOST_STATIC_ASSERT( ::boost::is_same<typename Traits::external_string_type,std::string>::value || ::boost::is_same<typename Traits::external_string_type,std::wstring>::value );
       
   154 
       
   155     public:
       
   156       // compiler generates copy constructor and copy assignment
       
   157 
       
   158       typedef basic_path<String, Traits> path_type;
       
   159       typedef String string_type;
       
   160       typedef typename String::value_type value_type;
       
   161       typedef Traits traits_type;
       
   162       typedef typename Traits::external_string_type external_string_type; 
       
   163 
       
   164       // constructors/destructor
       
   165       basic_path() {}
       
   166       basic_path( const string_type & s ) { operator/=( s ); }
       
   167       basic_path( const value_type * s )  { operator/=( s ); }
       
   168 #     ifndef BOOST_NO_MEMBER_TEMPLATES
       
   169         template <class InputIterator>
       
   170           basic_path( InputIterator first, InputIterator last )
       
   171             { append( first, last ); }
       
   172 #     endif
       
   173      ~basic_path() {}
       
   174 
       
   175       // assignments
       
   176       basic_path & operator=( const string_type & s )
       
   177       {
       
   178 #     if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, >= 310)
       
   179         m_path.clear();
       
   180 #     else
       
   181         m_path.erase( m_path.begin(), m_path.end() );
       
   182 #     endif
       
   183         operator/=( s ); 
       
   184         return *this;
       
   185       }
       
   186       basic_path & operator=( const value_type * s )
       
   187       { 
       
   188 #     if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, >= 310)
       
   189         m_path.clear();
       
   190 #     else
       
   191         m_path.erase( m_path.begin(), m_path.end() );
       
   192 #     endif
       
   193         operator/=( s ); 
       
   194         return *this;
       
   195       }
       
   196 #     ifndef BOOST_NO_MEMBER_TEMPLATES
       
   197         template <class InputIterator>
       
   198           basic_path & assign( InputIterator first, InputIterator last )
       
   199             { m_path.clear(); append( first, last ); return *this; }
       
   200 #     endif
       
   201 
       
   202       // modifiers
       
   203       basic_path & operator/=( const basic_path & rhs )  { return operator /=( rhs.string().c_str() ); }
       
   204       basic_path & operator/=( const string_type & rhs ) { return operator /=( rhs.c_str() ); }
       
   205       basic_path & operator/=( const value_type * s );
       
   206 #     ifndef BOOST_NO_MEMBER_TEMPLATES
       
   207         template <class InputIterator>
       
   208           basic_path & append( InputIterator first, InputIterator last );
       
   209 #     endif
       
   210       
       
   211       void swap( basic_path & rhs )
       
   212       {
       
   213         m_path.swap( rhs.m_path );
       
   214 #       ifdef BOOST_CYGWIN_PATH
       
   215           std::swap( m_cygwin_root, rhs.m_cygwin_root );
       
   216 #       endif
       
   217       }
       
   218 
       
   219       basic_path & remove_filename();
       
   220       basic_path & replace_extension( const string_type & new_extension = string_type() );
       
   221 
       
   222 # ifndef BOOST_FILESYSTEM_NO_DEPRECATED
       
   223       basic_path & remove_leaf() { return remove_filename(); }
       
   224 # endif
       
   225 
       
   226       // observers
       
   227       const string_type & string() const         { return m_path; }
       
   228       const string_type file_string() const;
       
   229       const string_type directory_string() const { return file_string(); }
       
   230 
       
   231       const external_string_type external_file_string() const { return Traits::to_external( *this, file_string() ); }
       
   232       const external_string_type external_directory_string() const { return Traits::to_external( *this, directory_string() ); }
       
   233 
       
   234       basic_path   root_path() const;
       
   235       string_type  root_name() const;
       
   236       string_type  root_directory() const;
       
   237       basic_path   relative_path() const;
       
   238       basic_path   parent_path() const;
       
   239       string_type  filename() const;
       
   240       string_type  stem() const;
       
   241       string_type  extension() const;
       
   242 
       
   243 # ifndef BOOST_FILESYSTEM_NO_DEPRECATED
       
   244       string_type  leaf() const            { return filename(); }
       
   245       basic_path   branch_path() const     { return parent_path(); }
       
   246       bool         has_leaf() const        { return !m_path.empty(); }
       
   247       bool         has_branch_path() const { return !parent_path().empty(); }
       
   248 # endif
       
   249 
       
   250       bool empty() const               { return m_path.empty(); } // name consistent with std containers
       
   251       bool is_complete() const;
       
   252       bool has_root_path() const;
       
   253       bool has_root_name() const;
       
   254       bool has_root_directory() const;
       
   255       bool has_relative_path() const   { return !relative_path().empty(); }
       
   256       bool has_filename() const        { return !m_path.empty(); }
       
   257       bool has_parent_path() const     { return !parent_path().empty(); }
       
   258 
       
   259       // iterators
       
   260       class iterator : public boost::iterator_facade<
       
   261         iterator,
       
   262         string_type const,
       
   263         boost::bidirectional_traversal_tag >
       
   264       {
       
   265       private:
       
   266         friend class boost::iterator_core_access;
       
   267         friend class boost::BOOST_FILESYSTEM_NAMESPACE::basic_path<String, Traits>;
       
   268 
       
   269         const string_type & dereference() const
       
   270           { return m_name; }
       
   271         bool equal( const iterator & rhs ) const
       
   272           { return m_path_ptr == rhs.m_path_ptr && m_pos == rhs.m_pos; }
       
   273 
       
   274         friend class boost::BOOST_FILESYSTEM_NAMESPACE::detail::iterator_helper<path_type>;
       
   275 
       
   276         void increment()
       
   277         { 
       
   278           boost::BOOST_FILESYSTEM_NAMESPACE::detail::iterator_helper<path_type>::do_increment(
       
   279             *this );
       
   280         }
       
   281         void decrement()
       
   282         { 
       
   283           boost::BOOST_FILESYSTEM_NAMESPACE::detail::iterator_helper<path_type>::do_decrement(
       
   284             *this );
       
   285         }
       
   286 
       
   287         string_type             m_name;     // current element
       
   288         const basic_path *      m_path_ptr; // path being iterated over
       
   289         typename string_type::size_type  m_pos;  // position of name in
       
   290                                             // path_ptr->string(). The
       
   291                                             // end() iterator is indicated by 
       
   292                                             // pos == path_ptr->m_path.size()
       
   293       }; // iterator
       
   294 
       
   295       typedef iterator const_iterator;
       
   296 
       
   297       iterator begin() const;
       
   298       iterator end() const;
       
   299 
       
   300     private:
       
   301       // Note: This is an implementation for POSIX and Windows, where there
       
   302       // are only minor differences between generic and native path grammars.
       
   303       // Private members might be quite different in other implementations,
       
   304       // particularly where there were wide differences between portable and
       
   305       // native path formats, or between file_string() and
       
   306       // directory_string() formats, or simply that the implementation
       
   307       // was willing expend additional memory to achieve greater speed for
       
   308       // some operations at the expense of other operations.
       
   309 
       
   310       string_type  m_path; // invariant: portable path grammar
       
   311                            // on Windows, backslashes converted to slashes
       
   312 
       
   313 #   ifdef BOOST_CYGWIN_PATH
       
   314       bool m_cygwin_root; // if present, m_path[0] was slash. note: initialization
       
   315                           // done by append
       
   316 #   endif  
       
   317 
       
   318       void m_append_separator_if_needed();
       
   319       void m_append( value_type value ); // converts Windows alt_separator
       
   320 
       
   321       // Was qualified; como433beta8 reports:
       
   322       //    warning #427-D: qualified name is not allowed in member declaration 
       
   323       friend class iterator;
       
   324       friend class boost::BOOST_FILESYSTEM_NAMESPACE::detail::iterator_helper<path_type>;
       
   325 
       
   326       // Deprecated features ease transition for existing code. Don't use these
       
   327       // in new code.
       
   328 # ifndef BOOST_FILESYSTEM_NO_DEPRECATED
       
   329     public:
       
   330       typedef bool (*name_check)( const std::string & name );
       
   331       basic_path( const string_type & str, name_check ) { operator/=( str ); }
       
   332       basic_path( const typename string_type::value_type * s, name_check )
       
   333         { operator/=( s );}
       
   334       string_type native_file_string() const { return file_string(); }
       
   335       string_type native_directory_string() const { return directory_string(); }
       
   336       static bool default_name_check_writable() { return false; } 
       
   337       static void default_name_check( name_check ) {}
       
   338       static name_check default_name_check() { return 0; }
       
   339       basic_path & canonize();
       
   340       basic_path & normalize();
       
   341 # endif
       
   342     };
       
   343 
       
   344   //  basic_path non-member functions  ---------------------------------------//
       
   345 
       
   346     template< class String, class Traits >
       
   347     inline void swap( basic_path<String, Traits> & lhs,
       
   348                basic_path<String, Traits> & rhs ) { lhs.swap( rhs ); }
       
   349 
       
   350     template< class String, class Traits >
       
   351     bool operator<( const basic_path<String, Traits> & lhs, const basic_path<String, Traits> & rhs )
       
   352     {
       
   353       return std::lexicographical_compare(
       
   354         lhs.begin(), lhs.end(), rhs.begin(), rhs.end() );
       
   355     }
       
   356 
       
   357     template< class String, class Traits >
       
   358     bool operator<( const typename basic_path<String, Traits>::string_type::value_type * lhs,
       
   359                     const basic_path<String, Traits> & rhs )
       
   360     {
       
   361       basic_path<String, Traits> tmp( lhs );
       
   362       return std::lexicographical_compare(
       
   363         tmp.begin(), tmp.end(), rhs.begin(), rhs.end() );
       
   364     }
       
   365 
       
   366     template< class String, class Traits >
       
   367     bool operator<( const typename basic_path<String, Traits>::string_type & lhs,
       
   368                     const basic_path<String, Traits> & rhs )
       
   369     {
       
   370       basic_path<String, Traits> tmp( lhs );
       
   371       return std::lexicographical_compare(
       
   372         tmp.begin(), tmp.end(), rhs.begin(), rhs.end() );
       
   373     }
       
   374 
       
   375     template< class String, class Traits >
       
   376     bool operator<( const basic_path<String, Traits> & lhs,
       
   377                     const typename basic_path<String, Traits>::string_type::value_type * rhs )
       
   378     {
       
   379       basic_path<String, Traits> tmp( rhs );
       
   380       return std::lexicographical_compare(
       
   381         lhs.begin(), lhs.end(), tmp.begin(), tmp.end() );
       
   382     }
       
   383 
       
   384     template< class String, class Traits >
       
   385     bool operator<( const basic_path<String, Traits> & lhs,
       
   386                     const typename basic_path<String, Traits>::string_type & rhs )
       
   387     {
       
   388       basic_path<String, Traits> tmp( rhs );
       
   389       return std::lexicographical_compare(
       
   390         lhs.begin(), lhs.end(), tmp.begin(), tmp.end() );
       
   391     }
       
   392 
       
   393     //  operator == uses string compare rather than !(lhs < rhs) && !(rhs < lhs) because
       
   394     //  the result is the same yet the direct string compare is much more efficient that
       
   395     //  lexicographical_compare, and lexicographical_compare used twice at that.
       
   396 
       
   397     template< class String, class Traits >
       
   398     inline bool operator==( const basic_path<String, Traits> & lhs, const basic_path<String, Traits> & rhs )
       
   399     { 
       
   400       return lhs.string() == rhs.string();
       
   401     }
       
   402 
       
   403     template< class String, class Traits >
       
   404     inline bool operator==( const typename basic_path<String, Traits>::string_type::value_type * lhs,
       
   405                     const basic_path<String, Traits> & rhs )
       
   406     {
       
   407       return lhs == rhs.string();
       
   408     }
       
   409 
       
   410     template< class String, class Traits >
       
   411     inline bool operator==( const typename basic_path<String, Traits>::string_type & lhs,
       
   412                     const basic_path<String, Traits> & rhs )
       
   413     {
       
   414       return lhs == rhs.string();
       
   415     }
       
   416 
       
   417     template< class String, class Traits >
       
   418     inline bool operator==( const basic_path<String, Traits> & lhs,
       
   419                     const typename basic_path<String, Traits>::string_type::value_type * rhs )
       
   420     {
       
   421       return lhs.string() == rhs;
       
   422     }
       
   423 
       
   424     template< class String, class Traits >
       
   425     inline bool operator==( const basic_path<String, Traits> & lhs,
       
   426                     const typename basic_path<String, Traits>::string_type & rhs )
       
   427     {
       
   428       return lhs.string() == rhs;
       
   429     }
       
   430 
       
   431     template< class String, class Traits >
       
   432     inline bool operator!=( const basic_path<String, Traits> & lhs,
       
   433       const basic_path<String, Traits> & rhs )
       
   434         { return !(lhs == rhs); }
       
   435     
       
   436     template< class String, class Traits >
       
   437     inline bool operator!=( const typename basic_path<String,
       
   438       Traits>::string_type::value_type * lhs,
       
   439         const basic_path<String, Traits> & rhs )
       
   440         { return !(lhs == rhs); }
       
   441 
       
   442     template< class String, class Traits >
       
   443     inline bool operator!=( const typename basic_path<String, Traits>::string_type & lhs,
       
   444       const basic_path<String, Traits> & rhs )
       
   445         { return !(lhs == rhs); }
       
   446 
       
   447     template< class String, class Traits >
       
   448     inline bool operator!=( const basic_path<String, Traits> & lhs,
       
   449       const typename basic_path<String, Traits>::string_type::value_type * rhs )
       
   450         { return !(lhs == rhs); }
       
   451 
       
   452     template< class String, class Traits >
       
   453     inline bool operator!=( const basic_path<String, Traits> & lhs,
       
   454       const typename basic_path<String, Traits>::string_type & rhs )
       
   455         { return !(lhs == rhs); }
       
   456 
       
   457     template< class String, class Traits >
       
   458     inline bool operator>( const basic_path<String, Traits> & lhs, const basic_path<String, Traits> & rhs ) { return rhs < lhs; }
       
   459     
       
   460     template< class String, class Traits >
       
   461     inline bool operator>( const typename basic_path<String, Traits>::string_type::value_type * lhs,
       
   462                     const basic_path<String, Traits> & rhs ) { return rhs < basic_path<String, Traits>(lhs); }
       
   463 
       
   464     template< class String, class Traits >
       
   465     inline bool operator>( const typename basic_path<String, Traits>::string_type & lhs,
       
   466                     const basic_path<String, Traits> & rhs ) { return rhs < basic_path<String, Traits>(lhs); }
       
   467 
       
   468     template< class String, class Traits >
       
   469     inline bool operator>( const basic_path<String, Traits> & lhs,
       
   470                     const typename basic_path<String, Traits>::string_type::value_type * rhs )
       
   471                     { return basic_path<String, Traits>(rhs) < lhs; }
       
   472 
       
   473     template< class String, class Traits >
       
   474     inline bool operator>( const basic_path<String, Traits> & lhs,
       
   475                     const typename basic_path<String, Traits>::string_type & rhs )
       
   476                     { return basic_path<String, Traits>(rhs) < lhs; }
       
   477 
       
   478     template< class String, class Traits >
       
   479     inline bool operator<=( const basic_path<String, Traits> & lhs, const basic_path<String, Traits> & rhs ) { return !(rhs < lhs); }
       
   480     
       
   481     template< class String, class Traits >
       
   482     inline bool operator<=( const typename basic_path<String, Traits>::string_type::value_type * lhs,
       
   483                     const basic_path<String, Traits> & rhs ) { return !(rhs < basic_path<String, Traits>(lhs)); }
       
   484 
       
   485     template< class String, class Traits >
       
   486     inline bool operator<=( const typename basic_path<String, Traits>::string_type & lhs,
       
   487                     const basic_path<String, Traits> & rhs ) { return !(rhs < basic_path<String, Traits>(lhs)); }
       
   488 
       
   489     template< class String, class Traits >
       
   490     inline bool operator<=( const basic_path<String, Traits> & lhs,
       
   491                     const typename basic_path<String, Traits>::string_type::value_type * rhs )
       
   492                     { return !(basic_path<String, Traits>(rhs) < lhs); }
       
   493 
       
   494     template< class String, class Traits >
       
   495     inline bool operator<=( const basic_path<String, Traits> & lhs,
       
   496                     const typename basic_path<String, Traits>::string_type & rhs )
       
   497                     { return !(basic_path<String, Traits>(rhs) < lhs); }
       
   498 
       
   499     template< class String, class Traits >
       
   500     inline bool operator>=( const basic_path<String, Traits> & lhs, const basic_path<String, Traits> & rhs ) { return !(lhs < rhs); }
       
   501     
       
   502     template< class String, class Traits >
       
   503     inline bool operator>=( const typename basic_path<String, Traits>::string_type::value_type * lhs,
       
   504                     const basic_path<String, Traits> & rhs ) { return !(lhs < basic_path<String, Traits>(rhs)); }
       
   505 
       
   506     template< class String, class Traits >
       
   507     inline bool operator>=( const typename basic_path<String, Traits>::string_type & lhs,
       
   508                     const basic_path<String, Traits> & rhs ) { return !(lhs < basic_path<String, Traits>(rhs)); }
       
   509 
       
   510     template< class String, class Traits >
       
   511     inline bool operator>=( const basic_path<String, Traits> & lhs,
       
   512                     const typename basic_path<String, Traits>::string_type::value_type * rhs )
       
   513                     { return !(basic_path<String, Traits>(lhs) < rhs); }
       
   514 
       
   515     template< class String, class Traits >
       
   516     inline bool operator>=( const basic_path<String, Traits> & lhs,
       
   517                     const typename basic_path<String, Traits>::string_type & rhs )
       
   518                     { return !(basic_path<String, Traits>(lhs) < rhs); }
       
   519 
       
   520     // operator /
       
   521 
       
   522     template< class String, class Traits >
       
   523     inline basic_path<String, Traits> operator/( 
       
   524       const basic_path<String, Traits> & lhs,
       
   525       const basic_path<String, Traits> & rhs )
       
   526       { return basic_path<String, Traits>( lhs ) /= rhs; }
       
   527 
       
   528     template< class String, class Traits >
       
   529     inline basic_path<String, Traits> operator/( 
       
   530       const basic_path<String, Traits> & lhs,
       
   531       const typename String::value_type * rhs )
       
   532       { return basic_path<String, Traits>( lhs ) /=
       
   533           basic_path<String, Traits>( rhs ); }
       
   534 
       
   535     template< class String, class Traits >
       
   536     inline basic_path<String, Traits> operator/( 
       
   537       const basic_path<String, Traits> & lhs, const String & rhs )
       
   538       { return basic_path<String, Traits>( lhs ) /=
       
   539           basic_path<String, Traits>( rhs ); }
       
   540 
       
   541     template< class String, class Traits >
       
   542     inline basic_path<String, Traits> operator/( 
       
   543       const typename String::value_type * lhs,
       
   544       const basic_path<String, Traits> & rhs )
       
   545       { return basic_path<String, Traits>( lhs ) /= rhs; }
       
   546 
       
   547     template< class String, class Traits >
       
   548     inline basic_path<String, Traits> operator/(
       
   549       const String & lhs, const basic_path<String, Traits> & rhs )
       
   550       { return basic_path<String, Traits>( lhs ) /= rhs; }
       
   551    
       
   552     //  inserters and extractors  --------------------------------------------//
       
   553 
       
   554 // bypass VC++ 7.0 and earlier, and broken Borland compilers
       
   555 # if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) && !BOOST_WORKAROUND(__BORLANDC__, < 0x610)
       
   556     template< class Path >
       
   557     std::basic_ostream< typename Path::string_type::value_type,
       
   558       typename Path::string_type::traits_type > &
       
   559       operator<<
       
   560       ( std::basic_ostream< typename Path::string_type::value_type,
       
   561       typename Path::string_type::traits_type >& os, const Path & ph )
       
   562     {
       
   563       os << ph.string();
       
   564       return os;
       
   565     }
       
   566 
       
   567     template< class Path >
       
   568     std::basic_istream< typename Path::string_type::value_type,
       
   569       typename Path::string_type::traits_type > &
       
   570       operator>>
       
   571       ( std::basic_istream< typename Path::string_type::value_type,
       
   572       typename Path::string_type::traits_type >& is, Path & ph )
       
   573     {
       
   574       typename Path::string_type str;
       
   575       is >> str;
       
   576       ph = str;
       
   577       return is;
       
   578     }
       
   579 # elif BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
       
   580     template< class String, class Traits >
       
   581     std::basic_ostream< BOOST_DEDUCED_TYPENAME String::value_type,
       
   582       BOOST_DEDUCED_TYPENAME String::traits_type > &
       
   583       operator<<
       
   584       ( std::basic_ostream< BOOST_DEDUCED_TYPENAME String::value_type,
       
   585           BOOST_DEDUCED_TYPENAME String::traits_type >& os, 
       
   586         const basic_path< String, Traits > & ph )
       
   587     {
       
   588       os << ph.string();
       
   589       return os;
       
   590     }
       
   591 
       
   592     template< class String, class Traits >
       
   593     std::basic_istream< BOOST_DEDUCED_TYPENAME String::value_type, 
       
   594       BOOST_DEDUCED_TYPENAME String::traits_type > &
       
   595       operator>>
       
   596       ( std::basic_istream< BOOST_DEDUCED_TYPENAME String::value_type,
       
   597           BOOST_DEDUCED_TYPENAME String::traits_type> & is,
       
   598         basic_path< String, Traits > & ph )
       
   599     {
       
   600       String str;
       
   601       is >> str;
       
   602       ph = str;
       
   603       return is;
       
   604     }
       
   605 # endif
       
   606 
       
   607     //  basic_filesystem_error helpers  --------------------------------------//
       
   608 
       
   609     //  Originally choice of implementation was done via specialization of
       
   610     //  basic_filesystem_error::what(). Several compilers (GCC, aCC, etc.)
       
   611     //  couldn't handle that, so the choice is now accomplished by overloading.
       
   612 
       
   613     namespace detail
       
   614     {
       
   615       // BOOST_FILESYSTEM_DECL version works for VC++ but not GCC. Go figure!
       
   616       inline
       
   617       const char * what( const char * sys_err_what,
       
   618         const path & path1_arg, const path & path2_arg, std::string & target )
       
   619       {
       
   620         try
       
   621         {
       
   622           if ( target.empty() )
       
   623           {
       
   624             target = sys_err_what;
       
   625             if ( !path1_arg.empty() )
       
   626             {
       
   627               target += ": \"";
       
   628               target += path1_arg.file_string();
       
   629               target += "\"";
       
   630             }
       
   631             if ( !path2_arg.empty() )
       
   632             {
       
   633               target += ", \"";
       
   634               target += path2_arg.file_string();
       
   635               target += "\"";
       
   636             }
       
   637           }
       
   638           return target.c_str();
       
   639         }
       
   640         catch (...)
       
   641         {
       
   642           return sys_err_what;
       
   643         }
       
   644       }
       
   645 
       
   646       template<class Path>
       
   647       const char * what( const char * sys_err_what,
       
   648         const Path & /*path1_arg*/, const Path & /*path2_arg*/, std::string & /*target*/ )
       
   649       {
       
   650         return sys_err_what;
       
   651       }
       
   652     }
       
   653 
       
   654     //  basic_filesystem_error  ----------------------------------------------//
       
   655 
       
   656     template<class Path>
       
   657     class basic_filesystem_error : public system::system_error
       
   658     {
       
   659     // see http://www.boost.org/more/error_handling.html for design rationale
       
   660     public:
       
   661       // compiler generates copy constructor and copy assignment
       
   662 
       
   663       typedef Path path_type;
       
   664 
       
   665       basic_filesystem_error( const std::string & what_arg,
       
   666         system::error_code ec );
       
   667 
       
   668       basic_filesystem_error( const std::string & what_arg,
       
   669         const path_type & path1_arg, system::error_code ec );
       
   670 
       
   671       basic_filesystem_error( const std::string & what_arg, const path_type & path1_arg,
       
   672         const path_type & path2_arg, system::error_code ec );
       
   673 
       
   674       ~basic_filesystem_error() throw() {}
       
   675 
       
   676       const path_type & path1() const
       
   677       {
       
   678         static const path_type empty_path;
       
   679         return m_imp_ptr.get() ? m_imp_ptr->m_path1 : empty_path ;
       
   680       }
       
   681       const path_type & path2() const
       
   682       {
       
   683         static const path_type empty_path;
       
   684         return m_imp_ptr.get() ? m_imp_ptr->m_path2 : empty_path ;
       
   685       }
       
   686 
       
   687       const char * what() const throw()
       
   688       { 
       
   689         if ( !m_imp_ptr.get() )
       
   690           return system::system_error::what();
       
   691         return detail::what( system::system_error::what(), m_imp_ptr->m_path1,
       
   692           m_imp_ptr->m_path2, m_imp_ptr->m_what );  
       
   693       }
       
   694 
       
   695     private:
       
   696       struct m_imp
       
   697       {
       
   698         path_type                 m_path1; // may be empty()
       
   699         path_type                 m_path2; // may be empty()
       
   700         std::string               m_what;  // not built until needed
       
   701       };
       
   702       boost::shared_ptr<m_imp> m_imp_ptr;
       
   703     };
       
   704 
       
   705     typedef basic_filesystem_error<path> filesystem_error;
       
   706 
       
   707 # ifndef BOOST_FILESYSTEM_NARROW_ONLY
       
   708     typedef basic_filesystem_error<wpath> wfilesystem_error;
       
   709 # endif
       
   710 
       
   711   //  path::name_checks  -----------------------------------------------------//
       
   712 
       
   713     BOOST_FILESYSTEM_DECL bool portable_posix_name( const std::string & name );
       
   714     BOOST_FILESYSTEM_DECL bool windows_name( const std::string & name );
       
   715     BOOST_FILESYSTEM_DECL bool portable_name( const std::string & name );
       
   716     BOOST_FILESYSTEM_DECL bool portable_directory_name( const std::string & name );
       
   717     BOOST_FILESYSTEM_DECL bool portable_file_name( const std::string & name );
       
   718     BOOST_FILESYSTEM_DECL bool native( const std::string & name );
       
   719     inline bool no_check( const std::string & )
       
   720       { return true; }
       
   721 
       
   722 // implementation  -----------------------------------------------------------//
       
   723 
       
   724     namespace detail
       
   725     {
       
   726 
       
   727       //  is_separator helper ------------------------------------------------//
       
   728 
       
   729       template<class Path>
       
   730       inline  bool is_separator( typename Path::string_type::value_type c )
       
   731       {
       
   732         return c == slash<Path>::value
       
   733 #     ifdef BOOST_WINDOWS_PATH
       
   734           || c == path_alt_separator<Path>::value
       
   735 #     endif
       
   736           ;
       
   737       }
       
   738 
       
   739       // filename_pos helper  ----------------------------------------------------//
       
   740 
       
   741       template<class String, class Traits>
       
   742       typename String::size_type filename_pos(
       
   743         const String & str, // precondition: portable generic path grammar
       
   744         typename String::size_type end_pos ) // end_pos is past-the-end position
       
   745       // return 0 if str itself is filename (or empty)
       
   746       {
       
   747         typedef typename
       
   748           boost::BOOST_FILESYSTEM_NAMESPACE::basic_path<String, Traits> path_type;
       
   749 
       
   750         // case: "//"
       
   751         if ( end_pos == 2 
       
   752           && str[0] == slash<path_type>::value
       
   753           && str[1] == slash<path_type>::value ) return 0;
       
   754 
       
   755         // case: ends in "/"
       
   756         if ( end_pos && str[end_pos-1] == slash<path_type>::value )
       
   757           return end_pos-1;
       
   758         
       
   759         // set pos to start of last element
       
   760         typename String::size_type pos(
       
   761           str.find_last_of( slash<path_type>::value, end_pos-1 ) );
       
   762 #       ifdef BOOST_WINDOWS_PATH
       
   763         if ( pos == String::npos )
       
   764           pos = str.find_last_of( path_alt_separator<path_type>::value, end_pos-1 );
       
   765         if ( pos == String::npos )
       
   766           pos = str.find_last_of( colon<path_type>::value, end_pos-2 );
       
   767 #       endif
       
   768 
       
   769         return ( pos == String::npos // path itself must be a filename (or empty)
       
   770           || (pos == 1 && str[0] == slash<path_type>::value) ) // or net
       
   771             ? 0 // so filename is entire string
       
   772             : pos + 1; // or starts after delimiter
       
   773       }
       
   774 
       
   775       // first_element helper  -----------------------------------------------//
       
   776       //   sets pos and len of first element, excluding extra separators
       
   777       //   if src.empty(), sets pos,len, to 0,0.
       
   778 
       
   779       template<class String, class Traits>
       
   780         void first_element(
       
   781           const String & src, // precondition: portable generic path grammar
       
   782           typename String::size_type & element_pos,
       
   783           typename String::size_type & element_size,
       
   784 #       if !BOOST_WORKAROUND( BOOST_MSVC, <= 1310 ) // VC++ 7.1
       
   785           typename String::size_type size = String::npos
       
   786 #       else
       
   787           typename String::size_type size = -1
       
   788 #       endif
       
   789           )
       
   790       {
       
   791         if ( size == String::npos ) size = src.size();
       
   792         element_pos = 0;
       
   793         element_size = 0;
       
   794         if ( src.empty() ) return;
       
   795 
       
   796         typedef typename boost::BOOST_FILESYSTEM_NAMESPACE::basic_path<String, Traits> path_type;
       
   797 
       
   798         typename String::size_type cur(0);
       
   799         
       
   800         // deal with // [network]
       
   801         if ( size >= 2 && src[0] == slash<path_type>::value
       
   802           && src[1] == slash<path_type>::value
       
   803           && (size == 2
       
   804             || src[2] != slash<path_type>::value) )
       
   805         { 
       
   806           cur += 2;
       
   807           element_size += 2;
       
   808         }
       
   809 
       
   810         // leading (not non-network) separator
       
   811         else if ( src[0] == slash<path_type>::value )
       
   812         {
       
   813           ++element_size;
       
   814           // bypass extra leading separators
       
   815           while ( cur+1 < size
       
   816             && src[cur+1] == slash<path_type>::value )
       
   817           {
       
   818             ++cur;
       
   819             ++element_pos;
       
   820           }
       
   821           return;
       
   822         }
       
   823 
       
   824         // at this point, we have either a plain name, a network name,
       
   825         // or (on Windows only) a device name
       
   826 
       
   827         // find the end
       
   828         while ( cur < size
       
   829 #         ifdef BOOST_WINDOWS_PATH
       
   830           && src[cur] != colon<path_type>::value
       
   831 #         endif
       
   832           && src[cur] != slash<path_type>::value )
       
   833         {
       
   834           ++cur;
       
   835           ++element_size;
       
   836         }
       
   837 
       
   838 #       ifdef BOOST_WINDOWS_PATH
       
   839         if ( cur == size ) return;
       
   840         // include device delimiter
       
   841         if ( src[cur] == colon<path_type>::value )
       
   842           { ++element_size; }
       
   843 #       endif
       
   844 
       
   845         return;
       
   846       }
       
   847 
       
   848       // root_directory_start helper  ----------------------------------------//
       
   849 
       
   850       template<class String, class Traits>
       
   851       typename String::size_type root_directory_start(
       
   852         const String & s, // precondition: portable generic path grammar
       
   853         typename String::size_type size )
       
   854       // return npos if no root_directory found
       
   855       {
       
   856         typedef typename boost::BOOST_FILESYSTEM_NAMESPACE::basic_path<String, Traits> path_type;
       
   857 
       
   858 #     ifdef BOOST_WINDOWS_PATH
       
   859         // case "c:/"
       
   860         if ( size > 2
       
   861           && s[1] == colon<path_type>::value
       
   862           && s[2] == slash<path_type>::value ) return 2;
       
   863 #     endif
       
   864 
       
   865         // case "//"
       
   866         if ( size == 2
       
   867           && s[0] == slash<path_type>::value
       
   868           && s[1] == slash<path_type>::value ) return String::npos;
       
   869 
       
   870         // case "//net {/}"
       
   871         if ( size > 3
       
   872           && s[0] == slash<path_type>::value
       
   873           && s[1] == slash<path_type>::value
       
   874           && s[2] != slash<path_type>::value )
       
   875         {
       
   876           typename String::size_type pos(
       
   877             s.find( slash<path_type>::value, 2 ) );
       
   878           return pos < size ? pos : String::npos;
       
   879         }
       
   880         
       
   881         // case "/"
       
   882         if ( size > 0 && s[0] == slash<path_type>::value ) return 0;
       
   883 
       
   884         return String::npos;
       
   885       }
       
   886 
       
   887       // is_non_root_slash helper  -------------------------------------------//
       
   888 
       
   889       template<class String, class Traits>
       
   890       bool is_non_root_slash( const String & str,
       
   891         typename String::size_type pos ) // pos is position of the slash
       
   892       {
       
   893         typedef typename
       
   894           boost::BOOST_FILESYSTEM_NAMESPACE::basic_path<String, Traits>
       
   895             path_type;
       
   896 
       
   897         assert( !str.empty() && str[pos] == slash<path_type>::value
       
   898           && "precondition violation" );
       
   899 
       
   900         // subsequent logic expects pos to be for leftmost slash of a set
       
   901         while ( pos > 0 && str[pos-1] == slash<path_type>::value )
       
   902           --pos;
       
   903 
       
   904         return  pos != 0
       
   905           && (pos <= 2 || str[1] != slash<path_type>::value
       
   906             || str.find( slash<path_type>::value, 2 ) != pos)
       
   907 #       ifdef BOOST_WINDOWS_PATH
       
   908           && (pos !=2 || str[1] != colon<path_type>::value)
       
   909 #       endif
       
   910             ;
       
   911       }
       
   912     } // namespace detail
       
   913 
       
   914     // decomposition functions  ----------------------------------------------//
       
   915 
       
   916     template<class String, class Traits>
       
   917     String basic_path<String, Traits>::filename() const
       
   918     {
       
   919       typename String::size_type end_pos(
       
   920         detail::filename_pos<String, Traits>( m_path, m_path.size() ) );
       
   921       return (m_path.size()
       
   922                 && end_pos
       
   923                 && m_path[end_pos] == slash<path_type>::value
       
   924                 && detail::is_non_root_slash< String, Traits >(m_path, end_pos))
       
   925         ? String( 1, dot<path_type>::value )
       
   926         : m_path.substr( end_pos );
       
   927     }
       
   928 
       
   929     template<class String, class Traits>
       
   930     String basic_path<String, Traits>::stem() const
       
   931     {
       
   932       string_type name = filename();
       
   933       typename string_type::size_type n = name.rfind('.');
       
   934       return name.substr(0, n);
       
   935     }
       
   936 
       
   937     template<class String, class Traits>
       
   938     String basic_path<String, Traits>::extension() const
       
   939     {
       
   940       string_type name = filename();
       
   941       typename string_type::size_type n = name.rfind('.');
       
   942       if (n != string_type::npos)
       
   943         return name.substr(n);
       
   944       else
       
   945         return string_type();
       
   946     }
       
   947 
       
   948     template<class String, class Traits>
       
   949     basic_path<String, Traits> basic_path<String, Traits>::parent_path() const
       
   950     {
       
   951       typename String::size_type end_pos(
       
   952         detail::filename_pos<String, Traits>( m_path, m_path.size() ) );
       
   953 
       
   954       bool filename_was_separator( m_path.size()
       
   955         && m_path[end_pos] == slash<path_type>::value );
       
   956 
       
   957       // skip separators unless root directory
       
   958       typename string_type::size_type root_dir_pos( detail::root_directory_start
       
   959         <string_type, traits_type>( m_path, end_pos ) );
       
   960       for ( ; 
       
   961         end_pos > 0
       
   962         && (end_pos-1) != root_dir_pos
       
   963         && m_path[end_pos-1] == slash<path_type>::value
       
   964         ;
       
   965         --end_pos ) {}
       
   966 
       
   967      return (end_pos == 1 && root_dir_pos == 0 && filename_was_separator)
       
   968        ? path_type()
       
   969        : path_type( m_path.substr( 0, end_pos ) );
       
   970     }
       
   971 
       
   972     template<class String, class Traits>
       
   973     basic_path<String, Traits> basic_path<String, Traits>::relative_path() const
       
   974     {
       
   975       iterator itr( begin() );
       
   976       for ( ; itr.m_pos != m_path.size()
       
   977           && (itr.m_name[0] == slash<path_type>::value
       
   978 #     ifdef BOOST_WINDOWS_PATH
       
   979           || itr.m_name[itr.m_name.size()-1]
       
   980             == colon<path_type>::value
       
   981 #     endif
       
   982              ); ++itr ) {}
       
   983 
       
   984       return basic_path<String, Traits>( m_path.substr( itr.m_pos ) );
       
   985     }
       
   986 
       
   987     template<class String, class Traits>
       
   988     String basic_path<String, Traits>::root_name() const
       
   989     {
       
   990       iterator itr( begin() );
       
   991 
       
   992       return ( itr.m_pos != m_path.size()
       
   993         && (
       
   994             ( itr.m_name.size() > 1
       
   995               && itr.m_name[0] == slash<path_type>::value
       
   996               && itr.m_name[1] == slash<path_type>::value
       
   997             )
       
   998 #     ifdef BOOST_WINDOWS_PATH
       
   999           || itr.m_name[itr.m_name.size()-1]
       
  1000             == colon<path_type>::value
       
  1001 #     endif
       
  1002            ) )
       
  1003         ? *itr
       
  1004         : String();
       
  1005     }
       
  1006 
       
  1007     template<class String, class Traits>
       
  1008     String basic_path<String, Traits>::root_directory() const
       
  1009     {
       
  1010       typename string_type::size_type start(
       
  1011         detail::root_directory_start<String, Traits>( m_path, m_path.size() ) );
       
  1012 
       
  1013       return start == string_type::npos
       
  1014         ? string_type()
       
  1015         : m_path.substr( start, 1 );
       
  1016     }
       
  1017 
       
  1018     template<class String, class Traits>
       
  1019     basic_path<String, Traits> basic_path<String, Traits>::root_path() const
       
  1020     {
       
  1021       // even on POSIX, root_name() is non-empty() on network paths
       
  1022       return basic_path<String, Traits>( root_name() ) /= root_directory();
       
  1023     }
       
  1024 
       
  1025     // path query functions  -------------------------------------------------//
       
  1026 
       
  1027     template<class String, class Traits>
       
  1028     inline bool basic_path<String, Traits>::is_complete() const
       
  1029     {
       
  1030 #   ifdef BOOST_WINDOWS_PATH
       
  1031       return has_root_name() && has_root_directory();
       
  1032 #   else
       
  1033       return has_root_directory();
       
  1034 #   endif
       
  1035     }
       
  1036 
       
  1037     template<class String, class Traits>
       
  1038     inline bool basic_path<String, Traits>::has_root_path() const
       
  1039     {
       
  1040       return !root_path().empty();
       
  1041     }
       
  1042 
       
  1043     template<class String, class Traits>
       
  1044     inline bool basic_path<String, Traits>::has_root_name() const
       
  1045     {
       
  1046       return !root_name().empty();
       
  1047     }
       
  1048 
       
  1049     template<class String, class Traits>
       
  1050     inline bool basic_path<String, Traits>::has_root_directory() const
       
  1051     {
       
  1052       return !root_directory().empty();
       
  1053     }
       
  1054 
       
  1055     // append  ---------------------------------------------------------------//
       
  1056 
       
  1057     template<class String, class Traits>
       
  1058     void basic_path<String, Traits>::m_append_separator_if_needed()
       
  1059     // requires: !empty()
       
  1060     {
       
  1061       if (
       
  1062 #       ifdef BOOST_WINDOWS_PATH
       
  1063         *(m_path.end()-1) != colon<path_type>::value && 
       
  1064 #       endif
       
  1065         *(m_path.end()-1) != slash<path_type>::value )
       
  1066       {
       
  1067         m_path += slash<path_type>::value;
       
  1068       }
       
  1069     }
       
  1070       
       
  1071     template<class String, class Traits>
       
  1072     void basic_path<String, Traits>::m_append( value_type value )
       
  1073     {
       
  1074 #   ifdef BOOST_CYGWIN_PATH
       
  1075       if ( m_path.empty() ) m_cygwin_root = (value == slash<path_type>::value);
       
  1076 #   endif
       
  1077 
       
  1078 #   ifdef BOOST_WINDOWS_PATH
       
  1079       // for BOOST_WINDOWS_PATH, convert alt_separator ('\') to separator ('/')
       
  1080       m_path += ( value == path_alt_separator<path_type>::value
       
  1081         ? slash<path_type>::value
       
  1082         : value );
       
  1083 #   else
       
  1084       m_path += value;
       
  1085 #   endif
       
  1086     }
       
  1087     
       
  1088     // except that it wouldn't work for BOOST_NO_MEMBER_TEMPLATES compilers,
       
  1089     // the append() member template could replace this code.
       
  1090     template<class String, class Traits>
       
  1091     basic_path<String, Traits> & basic_path<String, Traits>::operator /=
       
  1092       ( const value_type * next_p )
       
  1093     {
       
  1094       // ignore escape sequence on POSIX or Windows
       
  1095       if ( *next_p == slash<path_type>::value
       
  1096         && *(next_p+1) == slash<path_type>::value
       
  1097         && *(next_p+2) == colon<path_type>::value ) next_p += 3;
       
  1098       
       
  1099       // append slash<path_type>::value if needed
       
  1100       if ( !empty() && *next_p != 0
       
  1101         && !detail::is_separator<path_type>( *next_p ) )
       
  1102       { m_append_separator_if_needed(); }
       
  1103 
       
  1104       for ( ; *next_p != 0; ++next_p ) m_append( *next_p );
       
  1105       return *this;
       
  1106     }
       
  1107 
       
  1108 # ifndef BOOST_NO_MEMBER_TEMPLATES
       
  1109     template<class String, class Traits> template <class InputIterator>
       
  1110       basic_path<String, Traits> & basic_path<String, Traits>::append(
       
  1111         InputIterator first, InputIterator last )
       
  1112     {
       
  1113       // append slash<path_type>::value if needed
       
  1114       if ( !empty() && first != last
       
  1115         && !detail::is_separator<path_type>( *first ) )
       
  1116       { m_append_separator_if_needed(); }
       
  1117 
       
  1118       // song-and-dance to avoid violating InputIterator requirements
       
  1119       // (which prohibit lookahead) in detecting a possible escape sequence
       
  1120       // (escape sequences are simply ignored on POSIX and Windows)
       
  1121       bool was_escape_sequence(true);
       
  1122       std::size_t append_count(0);
       
  1123       typename String::size_type initial_pos( m_path.size() );
       
  1124 
       
  1125       for ( ; first != last && *first; ++first )
       
  1126       {
       
  1127         if ( append_count == 0 && *first != slash<path_type>::value )
       
  1128           was_escape_sequence = false;
       
  1129         if ( append_count == 1 && *first != slash<path_type>::value )
       
  1130           was_escape_sequence = false;
       
  1131         if ( append_count == 2 && *first != colon<path_type>::value )
       
  1132           was_escape_sequence = false;
       
  1133         m_append( *first );
       
  1134         ++append_count;
       
  1135       }
       
  1136 
       
  1137       // erase escape sequence if any
       
  1138       if ( was_escape_sequence && append_count >= 3 )
       
  1139         m_path.erase( initial_pos, 3 );
       
  1140 
       
  1141       return *this;
       
  1142     }
       
  1143 # endif
       
  1144 
       
  1145 # ifndef BOOST_FILESYSTEM_NO_DEPRECATED
       
  1146 
       
  1147     // canonize  ------------------------------------------------------------//
       
  1148 
       
  1149     template<class String, class Traits>
       
  1150     basic_path<String, Traits> & basic_path<String, Traits>::canonize()
       
  1151     {
       
  1152       static const typename string_type::value_type dot_str[]
       
  1153         = { dot<path_type>::value, 0 };
       
  1154 
       
  1155       if ( m_path.empty() ) return *this;
       
  1156         
       
  1157       path_type temp;
       
  1158 
       
  1159       for ( iterator itr( begin() ); itr != end(); ++itr )
       
  1160       {
       
  1161         temp /= *itr;
       
  1162       };
       
  1163 
       
  1164       if ( temp.empty() ) temp /= dot_str;
       
  1165       m_path = temp.m_path;
       
  1166       return *this;
       
  1167     }
       
  1168 
       
  1169     // normalize  ------------------------------------------------------------//
       
  1170 
       
  1171     template<class String, class Traits>
       
  1172     basic_path<String, Traits> & basic_path<String, Traits>::normalize()
       
  1173     {
       
  1174       static const typename string_type::value_type dot_str[]
       
  1175         = { dot<path_type>::value, 0 };
       
  1176 
       
  1177       if ( m_path.empty() ) return *this;
       
  1178         
       
  1179       path_type temp;
       
  1180       iterator start( begin() );
       
  1181       iterator last( end() );
       
  1182       iterator stop( last-- );
       
  1183       for ( iterator itr( start ); itr != stop; ++itr )
       
  1184       {
       
  1185         // ignore "." except at start and last
       
  1186         if ( itr->size() == 1
       
  1187           && (*itr)[0] == dot<path_type>::value
       
  1188           && itr != start
       
  1189           && itr != last ) continue;
       
  1190 
       
  1191         // ignore a name and following ".."
       
  1192         if ( !temp.empty()
       
  1193           && itr->size() == 2
       
  1194           && (*itr)[0] == dot<path_type>::value
       
  1195           && (*itr)[1] == dot<path_type>::value ) // dot dot
       
  1196         {
       
  1197           string_type lf( temp.filename() );  
       
  1198           if ( lf.size() > 0  
       
  1199             && (lf.size() != 1
       
  1200               || (lf[0] != dot<path_type>::value
       
  1201                 && lf[0] != slash<path_type>::value))
       
  1202             && (lf.size() != 2 
       
  1203               || (lf[0] != dot<path_type>::value
       
  1204                 && lf[1] != dot<path_type>::value
       
  1205 #             ifdef BOOST_WINDOWS_PATH
       
  1206                 && lf[1] != colon<path_type>::value
       
  1207 #             endif
       
  1208                  )
       
  1209                )
       
  1210             )
       
  1211           {
       
  1212             temp.remove_filename();
       
  1213             // if not root directory, must also remove "/" if any
       
  1214             if ( temp.m_path.size() > 0
       
  1215               && temp.m_path[temp.m_path.size()-1]
       
  1216                 == slash<path_type>::value )
       
  1217             {
       
  1218               typename string_type::size_type rds(
       
  1219                 detail::root_directory_start<String,Traits>( temp.m_path,
       
  1220                   temp.m_path.size() ) );
       
  1221               if ( rds == string_type::npos
       
  1222                 || rds != temp.m_path.size()-1 ) 
       
  1223                 { temp.m_path.erase( temp.m_path.size()-1 ); }
       
  1224             }
       
  1225 
       
  1226             iterator next( itr );
       
  1227             if ( temp.empty() && ++next != stop
       
  1228               && next == last && *last == dot_str ) temp /= dot_str;
       
  1229             continue;
       
  1230           }
       
  1231         }
       
  1232 
       
  1233         temp /= *itr;
       
  1234       };
       
  1235 
       
  1236       if ( temp.empty() ) temp /= dot_str;
       
  1237       m_path = temp.m_path;
       
  1238       return *this;
       
  1239     }
       
  1240 
       
  1241 # endif
       
  1242 
       
  1243     // modifiers  ------------------------------------------------------------//
       
  1244 
       
  1245     template<class String, class Traits>
       
  1246     basic_path<String, Traits> & basic_path<String, Traits>::remove_filename()
       
  1247     {
       
  1248       m_path.erase(
       
  1249         detail::filename_pos<String, Traits>( m_path, m_path.size() ) );
       
  1250       return *this;
       
  1251     }
       
  1252 
       
  1253     template<class String, class Traits>
       
  1254     basic_path<String, Traits> &
       
  1255     basic_path<String, Traits>::replace_extension( const string_type & new_ext )
       
  1256     {
       
  1257       // erase existing extension if any
       
  1258       string_type old_ext = extension();
       
  1259       if ( !old_ext.empty() )
       
  1260         m_path.erase( m_path.size() - old_ext.size() );
       
  1261 
       
  1262       if ( !new_ext.empty() && new_ext[0] != dot<path_type>::value )
       
  1263         m_path += dot<path_type>::value;
       
  1264 
       
  1265       m_path += new_ext;
       
  1266 
       
  1267       return *this;
       
  1268     }
       
  1269 
       
  1270 
       
  1271     // path conversion functions  --------------------------------------------//
       
  1272 
       
  1273     template<class String, class Traits>
       
  1274     const String
       
  1275     basic_path<String, Traits>::file_string() const
       
  1276     {
       
  1277 #   ifdef BOOST_WINDOWS_PATH
       
  1278       // for Windows, use the alternate separator, and bypass extra 
       
  1279       // root separators
       
  1280 
       
  1281       typename string_type::size_type root_dir_start(
       
  1282         detail::root_directory_start<String, Traits>( m_path, m_path.size() ) );
       
  1283       bool in_root( root_dir_start != string_type::npos );
       
  1284       String s;
       
  1285       for ( typename string_type::size_type pos( 0 );
       
  1286         pos != m_path.size(); ++pos )
       
  1287       {
       
  1288         // special case // [net]
       
  1289         if ( pos == 0 && m_path.size() > 1
       
  1290           && m_path[0] == slash<path_type>::value
       
  1291           && m_path[1] == slash<path_type>::value
       
  1292           && ( m_path.size() == 2 
       
  1293             || !detail::is_separator<path_type>( m_path[2] )
       
  1294              ) )
       
  1295         {
       
  1296           ++pos;
       
  1297           s += path_alt_separator<path_type>::value;
       
  1298           s += path_alt_separator<path_type>::value;
       
  1299           continue;
       
  1300         }   
       
  1301 
       
  1302         // bypass extra root separators
       
  1303         if ( in_root )
       
  1304         { 
       
  1305           if ( s.size() > 0
       
  1306             && s[s.size()-1] == path_alt_separator<path_type>::value
       
  1307             && m_path[pos] == slash<path_type>::value
       
  1308             ) continue;
       
  1309         }
       
  1310 
       
  1311         if ( m_path[pos] == slash<path_type>::value )
       
  1312           s += path_alt_separator<path_type>::value;
       
  1313         else
       
  1314           s += m_path[pos];
       
  1315 
       
  1316         if ( pos > root_dir_start
       
  1317           && m_path[pos] == slash<path_type>::value )
       
  1318           { in_root = false; }
       
  1319       }
       
  1320 #   ifdef BOOST_CYGWIN_PATH
       
  1321       if ( m_cygwin_root ) s[0] = slash<path_type>::value;
       
  1322 #   endif
       
  1323       return s;
       
  1324 #   else
       
  1325       return m_path;
       
  1326 #   endif
       
  1327     }
       
  1328 
       
  1329     // iterator functions  ---------------------------------------------------//
       
  1330 
       
  1331     template<class String, class Traits>
       
  1332     typename basic_path<String, Traits>::iterator basic_path<String, Traits>::begin() const
       
  1333     {
       
  1334       iterator itr;
       
  1335       itr.m_path_ptr = this;
       
  1336       typename string_type::size_type element_size;
       
  1337       detail::first_element<String, Traits>( m_path, itr.m_pos, element_size );
       
  1338       itr.m_name = m_path.substr( itr.m_pos, element_size );
       
  1339       return itr;
       
  1340     }
       
  1341 
       
  1342     template<class String, class Traits>
       
  1343     typename basic_path<String, Traits>::iterator basic_path<String, Traits>::end() const
       
  1344       {
       
  1345         iterator itr;
       
  1346         itr.m_path_ptr = this;
       
  1347         itr.m_pos = m_path.size();
       
  1348         return itr;
       
  1349       }
       
  1350 
       
  1351     namespace detail
       
  1352     {
       
  1353       //  do_increment  ------------------------------------------------------//
       
  1354 
       
  1355       template<class Path>
       
  1356       void iterator_helper<Path>::do_increment( iterator & itr )
       
  1357       {
       
  1358         typedef typename Path::string_type string_type;
       
  1359         typedef typename Path::traits_type traits_type;
       
  1360 
       
  1361         assert( itr.m_pos < itr.m_path_ptr->m_path.size() && "basic_path::iterator increment past end()" );
       
  1362 
       
  1363         bool was_net( itr.m_name.size() > 2
       
  1364           && itr.m_name[0] == slash<Path>::value
       
  1365           && itr.m_name[1] == slash<Path>::value
       
  1366           && itr.m_name[2] != slash<Path>::value );
       
  1367 
       
  1368         // increment to position past current element
       
  1369         itr.m_pos += itr.m_name.size();
       
  1370 
       
  1371         // if end reached, create end iterator
       
  1372         if ( itr.m_pos == itr.m_path_ptr->m_path.size() )
       
  1373         {
       
  1374           itr.m_name.erase( itr.m_name.begin(), itr.m_name.end() ); // VC++ 6.0 lib didn't supply clear() 
       
  1375           return;
       
  1376         }
       
  1377 
       
  1378         // process separator (Windows drive spec is only case not a separator)
       
  1379         if ( itr.m_path_ptr->m_path[itr.m_pos] == slash<Path>::value )
       
  1380         {
       
  1381           // detect root directory
       
  1382           if ( was_net
       
  1383   #       ifdef BOOST_WINDOWS_PATH
       
  1384             // case "c:/"
       
  1385             || itr.m_name[itr.m_name.size()-1] == colon<Path>::value
       
  1386   #       endif
       
  1387              )
       
  1388           {
       
  1389             itr.m_name = slash<Path>::value;
       
  1390             return;
       
  1391           }
       
  1392 
       
  1393           // bypass separators
       
  1394           while ( itr.m_pos != itr.m_path_ptr->m_path.size()
       
  1395             && itr.m_path_ptr->m_path[itr.m_pos] == slash<Path>::value )
       
  1396             { ++itr.m_pos; }
       
  1397 
       
  1398           // detect trailing separator, and treat it as ".", per POSIX spec
       
  1399           if ( itr.m_pos == itr.m_path_ptr->m_path.size()
       
  1400             && detail::is_non_root_slash< string_type, traits_type >(
       
  1401                 itr.m_path_ptr->m_path, itr.m_pos-1 ) ) 
       
  1402           {
       
  1403             --itr.m_pos;
       
  1404             itr.m_name = dot<Path>::value;
       
  1405             return;
       
  1406           }
       
  1407         }
       
  1408 
       
  1409         // get next element
       
  1410         typename string_type::size_type end_pos(
       
  1411           itr.m_path_ptr->m_path.find( slash<Path>::value, itr.m_pos ) );
       
  1412         itr.m_name = itr.m_path_ptr->m_path.substr( itr.m_pos, end_pos - itr.m_pos );
       
  1413       } 
       
  1414 
       
  1415       //  do_decrement  ------------------------------------------------------//
       
  1416 
       
  1417       template<class Path>
       
  1418       void iterator_helper<Path>::do_decrement( iterator & itr )
       
  1419       {                                                                                
       
  1420         assert( itr.m_pos && "basic_path::iterator decrement past begin()"  );
       
  1421 
       
  1422         typedef typename Path::string_type string_type;
       
  1423         typedef typename Path::traits_type traits_type;
       
  1424 
       
  1425         typename string_type::size_type end_pos( itr.m_pos );
       
  1426 
       
  1427         typename string_type::size_type root_dir_pos(
       
  1428           detail::root_directory_start<string_type, traits_type>(
       
  1429             itr.m_path_ptr->m_path, end_pos ) );
       
  1430 
       
  1431         // if at end and there was a trailing non-root '/', return "."
       
  1432         if ( itr.m_pos == itr.m_path_ptr->m_path.size()
       
  1433           && itr.m_path_ptr->m_path.size() > 1
       
  1434           && itr.m_path_ptr->m_path[itr.m_pos-1] == slash<Path>::value
       
  1435           && detail::is_non_root_slash< string_type, traits_type >(
       
  1436                itr.m_path_ptr->m_path, itr.m_pos-1 ) 
       
  1437            )
       
  1438         {
       
  1439           --itr.m_pos;
       
  1440             itr.m_name = dot<Path>::value;
       
  1441             return;
       
  1442         }
       
  1443 
       
  1444         // skip separators unless root directory
       
  1445         for ( 
       
  1446           ; 
       
  1447           end_pos > 0
       
  1448           && (end_pos-1) != root_dir_pos
       
  1449           && itr.m_path_ptr->m_path[end_pos-1] == slash<Path>::value
       
  1450           ;
       
  1451           --end_pos ) {}
       
  1452 
       
  1453         itr.m_pos = detail::filename_pos<string_type, traits_type>
       
  1454             ( itr.m_path_ptr->m_path, end_pos );
       
  1455         itr.m_name = itr.m_path_ptr->m_path.substr( itr.m_pos, end_pos - itr.m_pos );
       
  1456       }
       
  1457     } // namespace detail
       
  1458 
       
  1459     //  basic_filesystem_error implementation --------------------------------//
       
  1460 
       
  1461     template<class Path>
       
  1462     basic_filesystem_error<Path>::basic_filesystem_error(
       
  1463       const std::string & what_arg, system::error_code ec )
       
  1464       : system::system_error(ec, what_arg)
       
  1465     {
       
  1466       try
       
  1467       {
       
  1468         m_imp_ptr.reset( new m_imp );
       
  1469       }
       
  1470       catch (...) { m_imp_ptr.reset(); }
       
  1471     }
       
  1472 
       
  1473     template<class Path>
       
  1474     basic_filesystem_error<Path>::basic_filesystem_error(
       
  1475       const std::string & what_arg, const path_type & path1_arg,
       
  1476       system::error_code ec )
       
  1477       : system::system_error(ec, what_arg)
       
  1478     {
       
  1479       try
       
  1480       {
       
  1481         m_imp_ptr.reset( new m_imp );
       
  1482         m_imp_ptr->m_path1 = path1_arg;
       
  1483       }
       
  1484       catch (...) { m_imp_ptr.reset(); }
       
  1485     }
       
  1486 
       
  1487     template<class Path>
       
  1488     basic_filesystem_error<Path>::basic_filesystem_error(
       
  1489       const std::string & what_arg, const path_type & path1_arg,
       
  1490       const path_type & path2_arg, system::error_code ec )
       
  1491       : system::system_error(ec, what_arg)
       
  1492     {
       
  1493       try
       
  1494       {
       
  1495         m_imp_ptr.reset( new m_imp );
       
  1496         m_imp_ptr->m_path1 = path1_arg;
       
  1497         m_imp_ptr->m_path2 = path2_arg;
       
  1498       }
       
  1499       catch (...) { m_imp_ptr.reset(); }
       
  1500     }
       
  1501 
       
  1502   } // namespace BOOST_FILESYSTEM_NAMESPACE
       
  1503 } // namespace boost
       
  1504 
       
  1505 #include <boost/config/abi_suffix.hpp> // pops abi_prefix.hpp pragmas
       
  1506 
       
  1507 #endif // BOOST_FILESYSTEM_PATH_HPP