]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 |