1 | // filesystem path.hpp ---------------------------------------------------------------// |
2 | |
3 | // Copyright Beman Dawes 2002-2005, 2009 |
4 | // Copyright Vladimir Prus 2002 |
5 | |
6 | // Distributed under the Boost Software License, Version 1.0. |
7 | // See http://www.boost.org/LICENSE_1_0.txt |
8 | |
9 | // Library home page: http://www.boost.org/libs/filesystem |
10 | |
11 | // path::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 | #ifndef BOOST_FILESYSTEM_PATH_HPP |
16 | #define BOOST_FILESYSTEM_PATH_HPP |
17 | |
18 | #include <boost/config.hpp> |
19 | |
20 | # if defined( BOOST_NO_STD_WSTRING ) |
21 | # error Configuration not supported: Boost.Filesystem V3 and later requires std::wstring support |
22 | # endif |
23 | |
24 | #include <boost/filesystem/config.hpp> |
25 | #include <boost/filesystem/path_traits.hpp> // includes <cwchar> |
26 | #include <boost/system/error_code.hpp> |
27 | #include <boost/system/system_error.hpp> |
28 | #include <boost/iterator/iterator_facade.hpp> |
29 | #include <boost/shared_ptr.hpp> |
30 | #include <boost/io/detail/quoted_manip.hpp> |
31 | #include <boost/static_assert.hpp> |
32 | #include <boost/functional/hash_fwd.hpp> |
33 | #include <boost/type_traits/is_integral.hpp> |
34 | #include <string> |
35 | #include <iterator> |
36 | #include <cstring> |
37 | #include <iosfwd> |
38 | #include <stdexcept> |
39 | #include <cassert> |
40 | #include <locale> |
41 | #include <algorithm> |
42 | |
43 | #include <boost/config/abi_prefix.hpp> // must be the last #include |
44 | |
45 | namespace boost |
46 | { |
47 | namespace filesystem |
48 | { |
49 | |
50 | //------------------------------------------------------------------------------------// |
51 | // // |
52 | // class path // |
53 | // // |
54 | //------------------------------------------------------------------------------------// |
55 | |
56 | class BOOST_FILESYSTEM_DECL path |
57 | { |
58 | public: |
59 | |
60 | // value_type is the character type used by the operating system API to |
61 | // represent paths. |
62 | |
63 | # ifdef BOOST_WINDOWS_API |
64 | typedef wchar_t value_type; |
65 | BOOST_STATIC_CONSTEXPR value_type separator = L'/'; |
66 | BOOST_STATIC_CONSTEXPR value_type preferred_separator = L'\\'; |
67 | BOOST_STATIC_CONSTEXPR value_type dot = L'.'; |
68 | # else |
69 | typedef char value_type; |
70 | BOOST_STATIC_CONSTEXPR value_type separator = '/'; |
71 | BOOST_STATIC_CONSTEXPR value_type preferred_separator = '/'; |
72 | BOOST_STATIC_CONSTEXPR value_type dot = '.'; |
73 | # endif |
74 | typedef std::basic_string<value_type> string_type; |
75 | typedef std::codecvt<wchar_t, char, |
76 | std::mbstate_t> codecvt_type; |
77 | |
78 | |
79 | // ----- character encoding conversions ----- |
80 | |
81 | // Following the principle of least astonishment, path input arguments |
82 | // passed to or obtained from the operating system via objects of |
83 | // class path behave as if they were directly passed to or |
84 | // obtained from the O/S API, unless conversion is explicitly requested. |
85 | // |
86 | // POSIX specfies that path strings are passed unchanged to and from the |
87 | // API. Note that this is different from the POSIX command line utilities, |
88 | // which convert according to a locale. |
89 | // |
90 | // Thus for POSIX, char strings do not undergo conversion. wchar_t strings |
91 | // are converted to/from char using the path locale or, if a conversion |
92 | // argument is given, using a conversion object modeled on |
93 | // std::wstring_convert. |
94 | // |
95 | // The path locale, which is global to the thread, can be changed by the |
96 | // imbue() function. It is initialized to an implementation defined locale. |
97 | // |
98 | // For Windows, wchar_t strings do not undergo conversion. char strings |
99 | // are converted using the "ANSI" or "OEM" code pages, as determined by |
100 | // the AreFileApisANSI() function, or, if a conversion argument is given, |
101 | // using a conversion object modeled on std::wstring_convert. |
102 | // |
103 | // See m_pathname comments for further important rationale. |
104 | |
105 | // TODO: rules needed for operating systems that use / or . |
106 | // differently, or format directory paths differently from file paths. |
107 | // |
108 | // ********************************************************************************** |
109 | // |
110 | // More work needed: How to handle an operating system that may have |
111 | // slash characters or dot characters in valid filenames, either because |
112 | // it doesn't follow the POSIX standard, or because it allows MBCS |
113 | // filename encodings that may contain slash or dot characters. For |
114 | // example, ISO/IEC 2022 (JIS) encoding which allows switching to |
115 | // JIS x0208-1983 encoding. A valid filename in this set of encodings is |
116 | // 0x1B 0x24 0x42 [switch to X0208-1983] 0x24 0x2F [U+304F Kiragana letter KU] |
117 | // ^^^^ |
118 | // Note that 0x2F is the ASCII slash character |
119 | // |
120 | // ********************************************************************************** |
121 | |
122 | // Supported source arguments: half-open iterator range, container, c-array, |
123 | // and single pointer to null terminated string. |
124 | |
125 | // All source arguments except pointers to null terminated byte strings support |
126 | // multi-byte character strings which may have embedded nulls. Embedded null |
127 | // support is required for some Asian languages on Windows. |
128 | |
129 | // "const codecvt_type& cvt=codecvt()" default arguments are not used because this |
130 | // limits the impact of locale("") initialization failures on POSIX systems to programs |
131 | // that actually depend on locale(""). It further ensures that exceptions thrown |
132 | // as a result of such failues occur after main() has started, so can be caught. |
133 | |
134 | // ----- constructors ----- |
135 | |
136 | path() BOOST_NOEXCEPT {} |
137 | path(const path& p) : m_pathname(p.m_pathname) {} |
138 | |
139 | template <class Source> |
140 | path(Source const& source, |
141 | typename boost::enable_if<path_traits::is_pathable< |
142 | typename boost::decay<Source>::type> >::type* =0) |
143 | { |
144 | path_traits::dispatch(source, m_pathname); |
145 | } |
146 | |
147 | path(const value_type* s) : m_pathname(s) {} |
148 | path(value_type* s) : m_pathname(s) {} |
149 | path(const string_type& s) : m_pathname(s) {} |
150 | path(string_type& s) : m_pathname(s) {} |
151 | |
152 | // As of October 2015 the interaction between noexcept and =default is so troublesome |
153 | // for VC++, GCC, and probably other compilers, that =default is not used with noexcept |
154 | // functions. GCC is not even consistent for the same release on different platforms. |
155 | |
156 | # if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) |
157 | path(path&& p) BOOST_NOEXCEPT { m_pathname = std::move(p.m_pathname); } |
158 | path& operator=(path&& p) BOOST_NOEXCEPT |
159 | { m_pathname = std::move(p.m_pathname); return *this; } |
160 | # endif |
161 | |
162 | template <class Source> |
163 | path(Source const& source, const codecvt_type& cvt) |
164 | { |
165 | path_traits::dispatch(source, m_pathname, cvt); |
166 | } |
167 | |
168 | template <class InputIterator> |
169 | path(InputIterator begin, InputIterator end) |
170 | { |
171 | if (begin != end) |
172 | { |
173 | // convert requires contiguous string, so copy |
174 | std::basic_string<typename std::iterator_traits<InputIterator>::value_type> |
175 | seq(begin, end); |
176 | path_traits::convert(seq.c_str(), seq.c_str()+seq.size(), m_pathname); |
177 | } |
178 | } |
179 | |
180 | template <class InputIterator> |
181 | path(InputIterator begin, InputIterator end, const codecvt_type& cvt) |
182 | { |
183 | if (begin != end) |
184 | { |
185 | // convert requires contiguous string, so copy |
186 | std::basic_string<typename std::iterator_traits<InputIterator>::value_type> |
187 | seq(begin, end); |
188 | path_traits::convert(seq.c_str(), seq.c_str()+seq.size(), m_pathname, cvt); |
189 | } |
190 | } |
191 | |
192 | // ----- assignments ----- |
193 | |
194 | path& operator=(const path& p) |
195 | { |
196 | m_pathname = p.m_pathname; |
197 | return *this; |
198 | } |
199 | |
200 | template <class Source> |
201 | typename boost::enable_if<path_traits::is_pathable< |
202 | typename boost::decay<Source>::type>, path&>::type |
203 | operator=(Source const& source) |
204 | { |
205 | m_pathname.clear(); |
206 | path_traits::dispatch(source, m_pathname); |
207 | return *this; |
208 | } |
209 | |
210 | // value_type overloads |
211 | |
212 | path& operator=(const value_type* ptr) // required in case ptr overlaps *this |
213 | {m_pathname = ptr; return *this;} |
214 | path& operator=(value_type* ptr) // required in case ptr overlaps *this |
215 | {m_pathname = ptr; return *this;} |
216 | path& operator=(const string_type& s) {m_pathname = s; return *this;} |
217 | path& operator=(string_type& s) {m_pathname = s; return *this;} |
218 | |
219 | path& assign(const value_type* ptr, const codecvt_type&) // required in case ptr overlaps *this |
220 | {m_pathname = ptr; return *this;} |
221 | template <class Source> |
222 | path& assign(Source const& source, const codecvt_type& cvt) |
223 | { |
224 | m_pathname.clear(); |
225 | path_traits::dispatch(source, m_pathname, cvt); |
226 | return *this; |
227 | } |
228 | |
229 | template <class InputIterator> |
230 | path& assign(InputIterator begin, InputIterator end) |
231 | { |
232 | m_pathname.clear(); |
233 | if (begin != end) |
234 | { |
235 | std::basic_string<typename std::iterator_traits<InputIterator>::value_type> |
236 | seq(begin, end); |
237 | path_traits::convert(seq.c_str(), seq.c_str()+seq.size(), m_pathname); |
238 | } |
239 | return *this; |
240 | } |
241 | |
242 | template <class InputIterator> |
243 | path& assign(InputIterator begin, InputIterator end, const codecvt_type& cvt) |
244 | { |
245 | m_pathname.clear(); |
246 | if (begin != end) |
247 | { |
248 | std::basic_string<typename std::iterator_traits<InputIterator>::value_type> |
249 | seq(begin, end); |
250 | path_traits::convert(seq.c_str(), seq.c_str()+seq.size(), m_pathname, cvt); |
251 | } |
252 | return *this; |
253 | } |
254 | |
255 | // ----- concatenation ----- |
256 | |
257 | template <class Source> |
258 | typename boost::enable_if<path_traits::is_pathable< |
259 | typename boost::decay<Source>::type>, path&>::type |
260 | operator+=(Source const& source) |
261 | { |
262 | return concat(source); |
263 | } |
264 | |
265 | // value_type overloads. Same rationale as for constructors above |
266 | path& operator+=(const path& p) { m_pathname += p.m_pathname; return *this; } |
267 | path& operator+=(const value_type* ptr) { m_pathname += ptr; return *this; } |
268 | path& operator+=(value_type* ptr) { m_pathname += ptr; return *this; } |
269 | path& operator+=(const string_type& s) { m_pathname += s; return *this; } |
270 | path& operator+=(string_type& s) { m_pathname += s; return *this; } |
271 | path& operator+=(value_type c) { m_pathname += c; return *this; } |
272 | |
273 | template <class CharT> |
274 | typename boost::enable_if<is_integral<CharT>, path&>::type |
275 | operator+=(CharT c) |
276 | { |
277 | CharT tmp[2]; |
278 | tmp[0] = c; |
279 | tmp[1] = 0; |
280 | return concat(tmp); |
281 | } |
282 | |
283 | template <class Source> |
284 | path& concat(Source const& source) |
285 | { |
286 | path_traits::dispatch(source, m_pathname); |
287 | return *this; |
288 | } |
289 | |
290 | template <class Source> |
291 | path& concat(Source const& source, const codecvt_type& cvt) |
292 | { |
293 | path_traits::dispatch(source, m_pathname, cvt); |
294 | return *this; |
295 | } |
296 | |
297 | template <class InputIterator> |
298 | path& concat(InputIterator begin, InputIterator end) |
299 | { |
300 | if (begin == end) |
301 | return *this; |
302 | std::basic_string<typename std::iterator_traits<InputIterator>::value_type> |
303 | seq(begin, end); |
304 | path_traits::convert(seq.c_str(), seq.c_str()+seq.size(), m_pathname); |
305 | return *this; |
306 | } |
307 | |
308 | template <class InputIterator> |
309 | path& concat(InputIterator begin, InputIterator end, const codecvt_type& cvt) |
310 | { |
311 | if (begin == end) |
312 | return *this; |
313 | std::basic_string<typename std::iterator_traits<InputIterator>::value_type> |
314 | seq(begin, end); |
315 | path_traits::convert(seq.c_str(), seq.c_str()+seq.size(), m_pathname, cvt); |
316 | return *this; |
317 | } |
318 | |
319 | // ----- appends ----- |
320 | |
321 | // if a separator is added, it is the preferred separator for the platform; |
322 | // slash for POSIX, backslash for Windows |
323 | |
324 | path& operator/=(const path& p); |
325 | |
326 | template <class Source> |
327 | typename boost::enable_if<path_traits::is_pathable< |
328 | typename boost::decay<Source>::type>, path&>::type |
329 | operator/=(Source const& source) |
330 | { |
331 | return append(source); |
332 | } |
333 | |
334 | path& operator/=(const value_type* ptr); |
335 | path& operator/=(value_type* ptr) |
336 | { |
337 | return this->operator/=(const_cast<const value_type*>(ptr)); |
338 | } |
339 | path& operator/=(const string_type& s) { return this->operator/=(path(s)); } |
340 | path& operator/=(string_type& s) { return this->operator/=(path(s)); } |
341 | |
342 | path& append(const value_type* ptr) // required in case ptr overlaps *this |
343 | { |
344 | this->operator/=(ptr); |
345 | return *this; |
346 | } |
347 | |
348 | path& append(const value_type* ptr, const codecvt_type&) // required in case ptr overlaps *this |
349 | { |
350 | this->operator/=(ptr); |
351 | return *this; |
352 | } |
353 | |
354 | template <class Source> |
355 | path& append(Source const& source); |
356 | |
357 | template <class Source> |
358 | path& append(Source const& source, const codecvt_type& cvt); |
359 | |
360 | template <class InputIterator> |
361 | path& append(InputIterator begin, InputIterator end); |
362 | |
363 | template <class InputIterator> |
364 | path& append(InputIterator begin, InputIterator end, const codecvt_type& cvt); |
365 | |
366 | // ----- modifiers ----- |
367 | |
368 | void clear() BOOST_NOEXCEPT { m_pathname.clear(); } |
369 | path& make_preferred() |
370 | # ifdef BOOST_POSIX_API |
371 | { return *this; } // POSIX no effect |
372 | # else // BOOST_WINDOWS_API |
373 | ; // change slashes to backslashes |
374 | # endif |
375 | path& remove_filename(); |
376 | path& remove_trailing_separator(); |
377 | path& replace_extension(const path& new_extension = path()); |
378 | void swap(path& rhs) BOOST_NOEXCEPT { m_pathname.swap(rhs.m_pathname); } |
379 | |
380 | // ----- observers ----- |
381 | |
382 | // For operating systems that format file paths differently than directory |
383 | // paths, return values from observers are formatted as file names unless there |
384 | // is a trailing separator, in which case returns are formatted as directory |
385 | // paths. POSIX and Windows make no such distinction. |
386 | |
387 | // Implementations are permitted to return const values or const references. |
388 | |
389 | // The string or path returned by an observer are specified as being formatted |
390 | // as "native" or "generic". |
391 | // |
392 | // For POSIX, these are all the same format; slashes and backslashes are as input and |
393 | // are not modified. |
394 | // |
395 | // For Windows, native: as input; slashes and backslashes are not modified; |
396 | // this is the format of the internally stored string. |
397 | // generic: backslashes are converted to slashes |
398 | |
399 | // ----- native format observers ----- |
400 | |
401 | const string_type& native() const BOOST_NOEXCEPT { return m_pathname; } |
402 | const value_type* c_str() const BOOST_NOEXCEPT { return m_pathname.c_str(); } |
403 | string_type::size_type size() const BOOST_NOEXCEPT { return m_pathname.size(); } |
404 | |
405 | template <class String> |
406 | String string() const; |
407 | |
408 | template <class String> |
409 | String string(const codecvt_type& cvt) const; |
410 | |
411 | # ifdef BOOST_WINDOWS_API |
412 | const std::string string() const |
413 | { |
414 | std::string tmp; |
415 | if (!m_pathname.empty()) |
416 | path_traits::convert(&*m_pathname.begin(), &*m_pathname.begin()+m_pathname.size(), |
417 | tmp); |
418 | return tmp; |
419 | } |
420 | const std::string string(const codecvt_type& cvt) const |
421 | { |
422 | std::string tmp; |
423 | if (!m_pathname.empty()) |
424 | path_traits::convert(&*m_pathname.begin(), &*m_pathname.begin()+m_pathname.size(), |
425 | tmp, cvt); |
426 | return tmp; |
427 | } |
428 | |
429 | // string_type is std::wstring, so there is no conversion |
430 | const std::wstring& wstring() const { return m_pathname; } |
431 | const std::wstring& wstring(const codecvt_type&) const { return m_pathname; } |
432 | |
433 | # else // BOOST_POSIX_API |
434 | // string_type is std::string, so there is no conversion |
435 | const std::string& string() const { return m_pathname; } |
436 | const std::string& string(const codecvt_type&) const { return m_pathname; } |
437 | |
438 | const std::wstring wstring() const |
439 | { |
440 | std::wstring tmp; |
441 | if (!m_pathname.empty()) |
442 | path_traits::convert(&*m_pathname.begin(), &*m_pathname.begin()+m_pathname.size(), |
443 | tmp); |
444 | return tmp; |
445 | } |
446 | const std::wstring wstring(const codecvt_type& cvt) const |
447 | { |
448 | std::wstring tmp; |
449 | if (!m_pathname.empty()) |
450 | path_traits::convert(&*m_pathname.begin(), &*m_pathname.begin()+m_pathname.size(), |
451 | tmp, cvt); |
452 | return tmp; |
453 | } |
454 | |
455 | # endif |
456 | |
457 | // ----- generic format observers ----- |
458 | |
459 | // Experimental generic function returning generic formatted path (i.e. separators |
460 | // are forward slashes). Motivation: simpler than a family of generic_*string |
461 | // functions. |
462 | path generic_path() const |
463 | { |
464 | # ifdef BOOST_WINDOWS_API |
465 | path tmp; |
466 | std::replace_copy(m_pathname.begin(), m_pathname.end(), |
467 | std::back_inserter(tmp.m_pathname), L'\\', L'/'); |
468 | return tmp; |
469 | # else |
470 | return path(*this); |
471 | # endif |
472 | } |
473 | |
474 | template <class String> |
475 | String generic_string() const; |
476 | |
477 | template <class String> |
478 | String generic_string(const codecvt_type& cvt) const; |
479 | |
480 | # ifdef BOOST_WINDOWS_API |
481 | const std::string generic_string() const; |
482 | const std::string generic_string(const codecvt_type& cvt) const; |
483 | const std::wstring generic_wstring() const; |
484 | const std::wstring generic_wstring(const codecvt_type&) const { return generic_wstring(); }; |
485 | |
486 | # else // BOOST_POSIX_API |
487 | // On POSIX-like systems, the generic format is the same as the native format |
488 | const std::string& generic_string() const { return m_pathname; } |
489 | const std::string& generic_string(const codecvt_type&) const { return m_pathname; } |
490 | const std::wstring generic_wstring() const { return wstring(); } |
491 | const std::wstring generic_wstring(const codecvt_type& cvt) const { return wstring(cvt); } |
492 | |
493 | # endif |
494 | |
495 | // ----- compare ----- |
496 | |
497 | int compare(const path& p) const BOOST_NOEXCEPT; // generic, lexicographical |
498 | int compare(const std::string& s) const { return compare(path(s)); } |
499 | int compare(const value_type* s) const { return compare(path(s)); } |
500 | |
501 | // ----- decomposition ----- |
502 | |
503 | path root_path() const; |
504 | path root_name() const; // returns 0 or 1 element path |
505 | // even on POSIX, root_name() is non-empty() for network paths |
506 | path root_directory() const; // returns 0 or 1 element path |
507 | path relative_path() const; |
508 | path parent_path() const; |
509 | path filename() const; // returns 0 or 1 element path |
510 | path stem() const; // returns 0 or 1 element path |
511 | path extension() const; // returns 0 or 1 element path |
512 | |
513 | // ----- query ----- |
514 | |
515 | bool empty() const BOOST_NOEXCEPT{ return m_pathname.empty(); } |
516 | bool filename_is_dot() const; |
517 | bool filename_is_dot_dot() const; |
518 | bool has_root_path() const { return has_root_directory() || has_root_name(); } |
519 | bool has_root_name() const { return !root_name().empty(); } |
520 | bool has_root_directory() const { return !root_directory().empty(); } |
521 | bool has_relative_path() const { return !relative_path().empty(); } |
522 | bool has_parent_path() const { return !parent_path().empty(); } |
523 | bool has_filename() const { return !m_pathname.empty(); } |
524 | bool has_stem() const { return !stem().empty(); } |
525 | bool has_extension() const { return !extension().empty(); } |
526 | bool is_relative() const { return !is_absolute(); } |
527 | bool is_absolute() const |
528 | { |
529 | # ifdef BOOST_WINDOWS_API |
530 | return has_root_name() && has_root_directory(); |
531 | # else |
532 | return has_root_directory(); |
533 | # endif |
534 | } |
535 | |
536 | // ----- lexical operations ----- |
537 | |
538 | path lexically_normal() const; |
539 | path lexically_relative(const path& base) const; |
540 | path lexically_proximate(const path& base) const |
541 | { |
542 | path tmp(lexically_relative(base)); |
543 | return tmp.empty() ? *this : tmp; |
544 | } |
545 | |
546 | // ----- iterators ----- |
547 | |
548 | class iterator; |
549 | typedef iterator const_iterator; |
550 | class reverse_iterator; |
551 | typedef reverse_iterator const_reverse_iterator; |
552 | |
553 | iterator begin() const; |
554 | iterator end() const; |
555 | reverse_iterator rbegin() const; |
556 | reverse_iterator rend() const; |
557 | |
558 | // ----- static member functions ----- |
559 | |
560 | static std::locale imbue(const std::locale& loc); |
561 | static const codecvt_type& codecvt(); |
562 | |
563 | // ----- deprecated functions ----- |
564 | |
565 | # if defined(BOOST_FILESYSTEM_DEPRECATED) && defined(BOOST_FILESYSTEM_NO_DEPRECATED) |
566 | # error both BOOST_FILESYSTEM_DEPRECATED and BOOST_FILESYSTEM_NO_DEPRECATED are defined |
567 | # endif |
568 | |
569 | # if !defined(BOOST_FILESYSTEM_NO_DEPRECATED) |
570 | // recently deprecated functions supplied by default |
571 | path& normalize() { |
572 | path tmp(lexically_normal()); |
573 | m_pathname.swap(tmp.m_pathname); |
574 | return *this; |
575 | } |
576 | path& remove_leaf() { return remove_filename(); } |
577 | path leaf() const { return filename(); } |
578 | path branch_path() const { return parent_path(); } |
579 | path generic() const { return generic_path(); } |
580 | bool has_leaf() const { return !m_pathname.empty(); } |
581 | bool has_branch_path() const { return !parent_path().empty(); } |
582 | bool is_complete() const { return is_absolute(); } |
583 | # endif |
584 | |
585 | # if defined(BOOST_FILESYSTEM_DEPRECATED) |
586 | // deprecated functions with enough signature or semantic changes that they are |
587 | // not supplied by default |
588 | const std::string file_string() const { return string(); } |
589 | const std::string directory_string() const { return string(); } |
590 | const std::string native_file_string() const { return string(); } |
591 | const std::string native_directory_string() const { return string(); } |
592 | const string_type external_file_string() const { return native(); } |
593 | const string_type external_directory_string() const { return native(); } |
594 | |
595 | // older functions no longer supported |
596 | //typedef bool (*name_check)(const std::string & name); |
597 | //basic_path(const string_type& str, name_check) { operator/=(str); } |
598 | //basic_path(const typename string_type::value_type* s, name_check) |
599 | // { operator/=(s);} |
600 | //static bool default_name_check_writable() { return false; } |
601 | //static void default_name_check(name_check) {} |
602 | //static name_check default_name_check() { return 0; } |
603 | //basic_path& canonize(); |
604 | # endif |
605 | |
606 | //--------------------------------------------------------------------------------------// |
607 | // class path private members // |
608 | //--------------------------------------------------------------------------------------// |
609 | |
610 | private: |
611 | |
612 | # if defined(_MSC_VER) |
613 | # pragma warning(push) // Save warning settings |
614 | # pragma warning(disable : 4251) // disable warning: class 'std::basic_string<_Elem,_Traits,_Ax>' |
615 | # endif // needs to have dll-interface... |
616 | /* |
617 | m_pathname has the type, encoding, and format required by the native |
618 | operating system. Thus for POSIX and Windows there is no conversion for |
619 | passing m_pathname.c_str() to the O/S API or when obtaining a path from the |
620 | O/S API. POSIX encoding is unspecified other than for dot and slash |
621 | characters; POSIX just treats paths as a sequence of bytes. Windows |
622 | encoding is UCS-2 or UTF-16 depending on the version. |
623 | */ |
624 | string_type m_pathname; // Windows: as input; backslashes NOT converted to slashes, |
625 | // slashes NOT converted to backslashes |
626 | # if defined(_MSC_VER) |
627 | # pragma warning(pop) // restore warning settings. |
628 | # endif |
629 | |
630 | string_type::size_type m_append_separator_if_needed(); |
631 | // Returns: If separator is to be appended, m_pathname.size() before append. Otherwise 0. |
632 | // Note: An append is never performed if size()==0, so a returned 0 is unambiguous. |
633 | |
634 | void m_erase_redundant_separator(string_type::size_type sep_pos); |
635 | string_type::size_type m_parent_path_end() const; |
636 | |
637 | path& m_normalize(); |
638 | |
639 | // Was qualified; como433beta8 reports: |
640 | // warning #427-D: qualified name is not allowed in member declaration |
641 | friend class iterator; |
642 | friend bool operator<(const path& lhs, const path& rhs); |
643 | |
644 | // see path::iterator::increment/decrement comment below |
645 | static void m_path_iterator_increment(path::iterator & it); |
646 | static void m_path_iterator_decrement(path::iterator & it); |
647 | |
648 | }; // class path |
649 | |
650 | namespace detail |
651 | { |
652 | BOOST_FILESYSTEM_DECL |
653 | int lex_compare(path::iterator first1, path::iterator last1, |
654 | path::iterator first2, path::iterator last2); |
655 | BOOST_FILESYSTEM_DECL |
656 | const path& dot_path(); |
657 | BOOST_FILESYSTEM_DECL |
658 | const path& dot_dot_path(); |
659 | } |
660 | |
661 | # ifndef BOOST_FILESYSTEM_NO_DEPRECATED |
662 | typedef path wpath; |
663 | # endif |
664 | |
665 | //------------------------------------------------------------------------------------// |
666 | // class path::iterator // |
667 | //------------------------------------------------------------------------------------// |
668 | |
669 | class path::iterator |
670 | : public boost::iterator_facade< |
671 | path::iterator, |
672 | path const, |
673 | boost::bidirectional_traversal_tag > |
674 | { |
675 | private: |
676 | friend class boost::iterator_core_access; |
677 | friend class boost::filesystem::path; |
678 | friend class boost::filesystem::path::reverse_iterator; |
679 | friend void m_path_iterator_increment(path::iterator & it); |
680 | friend void m_path_iterator_decrement(path::iterator & it); |
681 | |
682 | const path& dereference() const { return m_element; } |
683 | |
684 | bool equal(const iterator & rhs) const |
685 | { |
686 | return m_path_ptr == rhs.m_path_ptr && m_pos == rhs.m_pos; |
687 | } |
688 | |
689 | // iterator_facade derived classes don't seem to like implementations in |
690 | // separate translation unit dll's, so forward to class path static members |
691 | void increment() { m_path_iterator_increment(*this); } |
692 | void decrement() { m_path_iterator_decrement(*this); } |
693 | |
694 | path m_element; // current element |
695 | const path* m_path_ptr; // path being iterated over |
696 | string_type::size_type m_pos; // position of m_element in |
697 | // m_path_ptr->m_pathname. |
698 | // if m_element is implicit dot, m_pos is the |
699 | // position of the last separator in the path. |
700 | // end() iterator is indicated by |
701 | // m_pos == m_path_ptr->m_pathname.size() |
702 | }; // path::iterator |
703 | |
704 | //------------------------------------------------------------------------------------// |
705 | // class path::reverse_iterator // |
706 | //------------------------------------------------------------------------------------// |
707 | |
708 | class path::reverse_iterator |
709 | : public boost::iterator_facade< |
710 | path::reverse_iterator, |
711 | path const, |
712 | boost::bidirectional_traversal_tag > |
713 | { |
714 | public: |
715 | |
716 | explicit reverse_iterator(iterator itr) : m_itr(itr) |
717 | { |
718 | if (itr != itr.m_path_ptr->begin()) |
719 | m_element = *--itr; |
720 | } |
721 | private: |
722 | friend class boost::iterator_core_access; |
723 | friend class boost::filesystem::path; |
724 | |
725 | const path& dereference() const { return m_element; } |
726 | bool equal(const reverse_iterator& rhs) const { return m_itr == rhs.m_itr; } |
727 | void increment() |
728 | { |
729 | --m_itr; |
730 | if (m_itr != m_itr.m_path_ptr->begin()) |
731 | { |
732 | iterator tmp = m_itr; |
733 | m_element = *--tmp; |
734 | } |
735 | } |
736 | void decrement() |
737 | { |
738 | m_element = *m_itr; |
739 | ++m_itr; |
740 | } |
741 | |
742 | iterator m_itr; |
743 | path m_element; |
744 | |
745 | }; // path::reverse_iterator |
746 | |
747 | //------------------------------------------------------------------------------------// |
748 | // // |
749 | // non-member functions // |
750 | // // |
751 | //------------------------------------------------------------------------------------// |
752 | |
753 | // std::lexicographical_compare would infinately recurse because path iterators |
754 | // yield paths, so provide a path aware version |
755 | inline bool lexicographical_compare(path::iterator first1, path::iterator last1, |
756 | path::iterator first2, path::iterator last2) |
757 | { return detail::lex_compare(first1, last1, first2, last2) < 0; } |
758 | |
759 | inline bool operator==(const path& lhs, const path& rhs) {return lhs.compare(rhs) == 0;} |
760 | inline bool operator==(const path& lhs, const path::string_type& rhs) {return lhs.compare(rhs) == 0;} |
761 | inline bool operator==(const path::string_type& lhs, const path& rhs) {return rhs.compare(lhs) == 0;} |
762 | inline bool operator==(const path& lhs, const path::value_type* rhs) {return lhs.compare(rhs) == 0;} |
763 | inline bool operator==(const path::value_type* lhs, const path& rhs) {return rhs.compare(lhs) == 0;} |
764 | |
765 | inline bool operator!=(const path& lhs, const path& rhs) {return lhs.compare(rhs) != 0;} |
766 | inline bool operator!=(const path& lhs, const path::string_type& rhs) {return lhs.compare(rhs) != 0;} |
767 | inline bool operator!=(const path::string_type& lhs, const path& rhs) {return rhs.compare(lhs) != 0;} |
768 | inline bool operator!=(const path& lhs, const path::value_type* rhs) {return lhs.compare(rhs) != 0;} |
769 | inline bool operator!=(const path::value_type* lhs, const path& rhs) {return rhs.compare(lhs) != 0;} |
770 | |
771 | // TODO: why do == and != have additional overloads, but the others don't? |
772 | |
773 | inline bool operator<(const path& lhs, const path& rhs) {return lhs.compare(rhs) < 0;} |
774 | inline bool operator<=(const path& lhs, const path& rhs) {return !(rhs < lhs);} |
775 | inline bool operator> (const path& lhs, const path& rhs) {return rhs < lhs;} |
776 | inline bool operator>=(const path& lhs, const path& rhs) {return !(lhs < rhs);} |
777 | |
778 | inline std::size_t hash_value(const path& x) |
779 | { |
780 | # ifdef BOOST_WINDOWS_API |
781 | std::size_t seed = 0; |
782 | for(const path::value_type* it = x.c_str(); *it; ++it) |
783 | hash_combine(seed, *it == '/' ? L'\\' : *it); |
784 | return seed; |
785 | # else // BOOST_POSIX_API |
786 | return hash_range(x.native().begin(), x.native().end()); |
787 | # endif |
788 | } |
789 | |
790 | inline void swap(path& lhs, path& rhs) { lhs.swap(rhs); } |
791 | |
792 | inline path operator/(const path& lhs, const path& rhs) { return path(lhs) /= rhs; } |
793 | |
794 | // inserters and extractors |
795 | // use boost::io::quoted() to handle spaces in paths |
796 | // use '&' as escape character to ease use for Windows paths |
797 | |
798 | template <class Char, class Traits> |
799 | inline std::basic_ostream<Char, Traits>& |
800 | operator<<(std::basic_ostream<Char, Traits>& os, const path& p) |
801 | { |
802 | return os |
803 | << boost::io::quoted(p.template string<std::basic_string<Char> >(), static_cast<Char>('&')); |
804 | } |
805 | |
806 | template <class Char, class Traits> |
807 | inline std::basic_istream<Char, Traits>& |
808 | operator>>(std::basic_istream<Char, Traits>& is, path& p) |
809 | { |
810 | std::basic_string<Char> str; |
811 | is >> boost::io::quoted(str, static_cast<Char>('&')); |
812 | p = str; |
813 | return is; |
814 | } |
815 | |
816 | // name_checks |
817 | |
818 | // These functions are holdovers from version 1. It isn't clear they have much |
819 | // usefulness, or how to generalize them for later versions. |
820 | |
821 | BOOST_FILESYSTEM_DECL bool portable_posix_name(const std::string & name); |
822 | BOOST_FILESYSTEM_DECL bool windows_name(const std::string & name); |
823 | BOOST_FILESYSTEM_DECL bool portable_name(const std::string & name); |
824 | BOOST_FILESYSTEM_DECL bool portable_directory_name(const std::string & name); |
825 | BOOST_FILESYSTEM_DECL bool portable_file_name(const std::string & name); |
826 | BOOST_FILESYSTEM_DECL bool native(const std::string & name); |
827 | |
828 | namespace detail |
829 | { |
830 | // For POSIX, is_directory_separator() and is_element_separator() are identical since |
831 | // a forward slash is the only valid directory separator and also the only valid |
832 | // element separator. For Windows, forward slash and back slash are the possible |
833 | // directory separators, but colon (example: "c:foo") is also an element separator. |
834 | |
835 | inline bool is_directory_separator(path::value_type c) BOOST_NOEXCEPT |
836 | { |
837 | return c == path::separator |
838 | # ifdef BOOST_WINDOWS_API |
839 | || c == path::preferred_separator |
840 | # endif |
841 | ; |
842 | } |
843 | inline bool is_element_separator(path::value_type c) BOOST_NOEXCEPT |
844 | { |
845 | return c == path::separator |
846 | # ifdef BOOST_WINDOWS_API |
847 | || c == path::preferred_separator || c == L':' |
848 | # endif |
849 | ; |
850 | } |
851 | } // namespace detail |
852 | |
853 | //------------------------------------------------------------------------------------// |
854 | // class path miscellaneous function implementations // |
855 | //------------------------------------------------------------------------------------// |
856 | |
857 | inline path::reverse_iterator path::rbegin() const { return reverse_iterator(end()); } |
858 | inline path::reverse_iterator path::rend() const { return reverse_iterator(begin()); } |
859 | |
860 | inline bool path::filename_is_dot() const |
861 | { |
862 | // implicit dot is tricky, so actually call filename(); see path::filename() example |
863 | // in reference.html |
864 | path p(filename()); |
865 | return p.size() == 1 && *p.c_str() == dot; |
866 | } |
867 | |
868 | inline bool path::filename_is_dot_dot() const |
869 | { |
870 | return size() >= 2 && m_pathname[size()-1] == dot && m_pathname[size()-2] == dot |
871 | && (m_pathname.size() == 2 || detail::is_element_separator(m_pathname[size()-3])); |
872 | // use detail::is_element_separator() rather than detail::is_directory_separator |
873 | // to deal with "c:.." edge case on Windows when ':' acts as a separator |
874 | } |
875 | |
876 | //--------------------------------------------------------------------------------------// |
877 | // class path member template implementation // |
878 | //--------------------------------------------------------------------------------------// |
879 | |
880 | template <class InputIterator> |
881 | path& path::append(InputIterator begin, InputIterator end) |
882 | { |
883 | if (begin == end) |
884 | return *this; |
885 | string_type::size_type sep_pos(m_append_separator_if_needed()); |
886 | std::basic_string<typename std::iterator_traits<InputIterator>::value_type> |
887 | seq(begin, end); |
888 | path_traits::convert(seq.c_str(), seq.c_str()+seq.size(), m_pathname); |
889 | if (sep_pos) |
890 | m_erase_redundant_separator(sep_pos); |
891 | return *this; |
892 | } |
893 | |
894 | template <class InputIterator> |
895 | path& path::append(InputIterator begin, InputIterator end, const codecvt_type& cvt) |
896 | { |
897 | if (begin == end) |
898 | return *this; |
899 | string_type::size_type sep_pos(m_append_separator_if_needed()); |
900 | std::basic_string<typename std::iterator_traits<InputIterator>::value_type> |
901 | seq(begin, end); |
902 | path_traits::convert(seq.c_str(), seq.c_str()+seq.size(), m_pathname, cvt); |
903 | if (sep_pos) |
904 | m_erase_redundant_separator(sep_pos); |
905 | return *this; |
906 | } |
907 | |
908 | template <class Source> |
909 | path& path::append(Source const& source) |
910 | { |
911 | if (path_traits::empty(source)) |
912 | return *this; |
913 | string_type::size_type sep_pos(m_append_separator_if_needed()); |
914 | path_traits::dispatch(source, m_pathname); |
915 | if (sep_pos) |
916 | m_erase_redundant_separator(sep_pos); |
917 | return *this; |
918 | } |
919 | |
920 | template <class Source> |
921 | path& path::append(Source const& source, const codecvt_type& cvt) |
922 | { |
923 | if (path_traits::empty(source)) |
924 | return *this; |
925 | string_type::size_type sep_pos(m_append_separator_if_needed()); |
926 | path_traits::dispatch(source, m_pathname, cvt); |
927 | if (sep_pos) |
928 | m_erase_redundant_separator(sep_pos); |
929 | return *this; |
930 | } |
931 | |
932 | //--------------------------------------------------------------------------------------// |
933 | // class path member template specializations // |
934 | //--------------------------------------------------------------------------------------// |
935 | |
936 | template <> inline |
937 | std::string path::string<std::string>() const |
938 | { return string(); } |
939 | |
940 | template <> inline |
941 | std::wstring path::string<std::wstring>() const |
942 | { return wstring(); } |
943 | |
944 | template <> inline |
945 | std::string path::string<std::string>(const codecvt_type& cvt) const |
946 | { return string(cvt); } |
947 | |
948 | template <> inline |
949 | std::wstring path::string<std::wstring>(const codecvt_type& cvt) const |
950 | { return wstring(cvt); } |
951 | |
952 | template <> inline |
953 | std::string path::generic_string<std::string>() const |
954 | { return generic_string(); } |
955 | |
956 | template <> inline |
957 | std::wstring path::generic_string<std::wstring>() const |
958 | { return generic_wstring(); } |
959 | |
960 | template <> inline |
961 | std::string path::generic_string<std::string>(const codecvt_type& cvt) const |
962 | { return generic_string(cvt); } |
963 | |
964 | template <> inline |
965 | std::wstring path::generic_string<std::wstring>(const codecvt_type& cvt) const |
966 | { return generic_wstring(cvt); } |
967 | |
968 | //--------------------------------------------------------------------------------------// |
969 | // path_traits convert function implementations // |
970 | // requiring path::codecvt() be visable // |
971 | //--------------------------------------------------------------------------------------// |
972 | |
973 | namespace path_traits |
974 | { // without codecvt |
975 | |
976 | inline |
977 | void convert(const char* from, |
978 | const char* from_end, // 0 for null terminated MBCS |
979 | std::wstring & to) |
980 | { |
981 | convert(from, from_end, to, path::codecvt()); |
982 | } |
983 | |
984 | inline |
985 | void convert(const wchar_t* from, |
986 | const wchar_t* from_end, // 0 for null terminated MBCS |
987 | std::string & to) |
988 | { |
989 | convert(from, from_end, to, path::codecvt()); |
990 | } |
991 | |
992 | inline |
993 | void convert(const char* from, |
994 | std::wstring & to) |
995 | { |
996 | BOOST_ASSERT(from); |
997 | convert(from, 0, to, path::codecvt()); |
998 | } |
999 | |
1000 | inline |
1001 | void convert(const wchar_t* from, |
1002 | std::string & to) |
1003 | { |
1004 | BOOST_ASSERT(from); |
1005 | convert(from, 0, to, path::codecvt()); |
1006 | } |
1007 | } // namespace path_traits |
1008 | } // namespace filesystem |
1009 | } // namespace boost |
1010 | |
1011 | //----------------------------------------------------------------------------// |
1012 | |
1013 | #include <boost/config/abi_suffix.hpp> // pops abi_prefix.hpp pragmas |
1014 | |
1015 | #endif // BOOST_FILESYSTEM_PATH_HPP |
1016 | |