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