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