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