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