]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/filesystem/src/path.cpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / libs / filesystem / src / path.cpp
CommitLineData
7c673cae
FG
1// filesystem path.cpp ------------------------------------------------------------- //
2
3// Copyright Beman Dawes 2008
4
5// Distributed under the Boost Software License, Version 1.0.
6// See http://www.boost.org/LICENSE_1_0.txt
7
8// Library home page: http://www.boost.org/libs/filesystem
9
20effc67 10#include "platform_config.hpp"
92f5a8d4 11
7c673cae
FG
12// Old standard library configurations, particularly MingGW, don't support wide strings.
13// Report this with an explicit error message.
14#include <boost/config.hpp>
15# if defined( BOOST_NO_STD_WSTRING )
16# error Configuration not supported: Boost.Filesystem V3 and later requires std::wstring support
17# endif
18
7c673cae
FG
19#include <boost/filesystem/path.hpp>
20#include <boost/filesystem/operations.hpp> // for filesystem_error
21#include <boost/scoped_array.hpp>
22#include <boost/system/error_code.hpp>
23#include <boost/assert.hpp>
24#include <algorithm>
92f5a8d4
TL
25#include <iterator>
26#include <utility>
7c673cae
FG
27#include <cstddef>
28#include <cstring>
29#include <cassert>
30
31#ifdef BOOST_WINDOWS_API
32# include "windows_file_codecvt.hpp"
33# include <windows.h>
34#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \
35 || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
36# include <boost/filesystem/detail/utf8_codecvt_facet.hpp>
37#endif
38
39#ifdef BOOST_FILESYSTEM_DEBUG
40# include <iostream>
41# include <iomanip>
42#endif
43
44namespace fs = boost::filesystem;
45
46using boost::filesystem::path;
47
48using std::string;
49using std::wstring;
50
51using boost::system::error_code;
52
53//--------------------------------------------------------------------------------------//
54// //
55// class path helpers //
56// //
57//--------------------------------------------------------------------------------------//
58
59namespace
60{
61 //------------------------------------------------------------------------------------//
62 // miscellaneous class path helpers //
63 //------------------------------------------------------------------------------------//
64
65 typedef path::value_type value_type;
66 typedef path::string_type string_type;
67 typedef string_type::size_type size_type;
68
69# ifdef BOOST_WINDOWS_API
70
7c673cae
FG
71 const wchar_t* const separators = L"/\\";
72 const wchar_t* separator_string = L"/";
73 const wchar_t* preferred_separator_string = L"\\";
74 const wchar_t colon = L':';
7c673cae
FG
75 const wchar_t questionmark = L'?';
76
77 inline bool is_letter(wchar_t c)
78 {
79 return (c >= L'a' && c <=L'z') || (c >= L'A' && c <=L'Z');
80 }
81
82# else
83
7c673cae
FG
84 const char* const separators = "/";
85 const char* separator_string = "/";
86 const char* preferred_separator_string = "/";
7c673cae
FG
87
88# endif
89
7c673cae
FG
90 bool is_root_separator(const string_type& str, size_type pos);
91 // pos is position of the separator
92
93 size_type filename_pos(const string_type& str,
94 size_type end_pos); // end_pos is past-the-end position
95 // Returns: 0 if str itself is filename (or empty)
96
97 size_type root_directory_start(const string_type& path, size_type size);
98 // Returns: npos if no root_directory found
99
100 void first_element(
101 const string_type& src,
102 size_type& element_pos,
103 size_type& element_size,
104# if !BOOST_WORKAROUND(BOOST_MSVC, <= 1310) // VC++ 7.1
105 size_type size = string_type::npos
106# else
107 size_type size = -1
108# endif
109 );
110
111} // unnamed namespace
112
113//--------------------------------------------------------------------------------------//
114// //
115// class path implementation //
116// //
117//--------------------------------------------------------------------------------------//
118
119namespace boost
120{
121namespace filesystem
122{
92f5a8d4
TL
123
124 BOOST_FILESYSTEM_DECL path& path::operator/=(const path& p)
7c673cae
FG
125 {
126 if (p.empty())
127 return *this;
128 if (this == &p) // self-append
129 {
130 path rhs(p);
b32b8144 131 if (!detail::is_directory_separator(rhs.m_pathname[0]))
7c673cae
FG
132 m_append_separator_if_needed();
133 m_pathname += rhs.m_pathname;
134 }
135 else
136 {
b32b8144 137 if (!detail::is_directory_separator(*p.m_pathname.begin()))
7c673cae
FG
138 m_append_separator_if_needed();
139 m_pathname += p.m_pathname;
140 }
141 return *this;
142 }
143
92f5a8d4 144 BOOST_FILESYSTEM_DECL path& path::operator/=(const value_type* ptr)
7c673cae
FG
145 {
146 if (!*ptr)
147 return *this;
148 if (ptr >= m_pathname.data()
149 && ptr < m_pathname.data() + m_pathname.size()) // overlapping source
150 {
151 path rhs(ptr);
b32b8144 152 if (!detail::is_directory_separator(rhs.m_pathname[0]))
7c673cae
FG
153 m_append_separator_if_needed();
154 m_pathname += rhs.m_pathname;
155 }
156 else
157 {
b32b8144 158 if (!detail::is_directory_separator(*ptr))
7c673cae
FG
159 m_append_separator_if_needed();
160 m_pathname += ptr;
161 }
162 return *this;
163 }
164
7c673cae
FG
165# ifdef BOOST_WINDOWS_API
166
92f5a8d4 167 BOOST_FILESYSTEM_DECL path path::generic_path() const
7c673cae
FG
168 {
169 path tmp(*this);
170 std::replace(tmp.m_pathname.begin(), tmp.m_pathname.end(), L'\\', L'/');
92f5a8d4 171 return tmp;
7c673cae
FG
172 }
173
92f5a8d4 174# endif // BOOST_WINDOWS_API
7c673cae 175
92f5a8d4
TL
176 BOOST_FILESYSTEM_DECL int path::compare(const path& p) const BOOST_NOEXCEPT
177 {
178 return detail::lex_compare(begin(), end(), p.begin(), p.end());
7c673cae
FG
179 }
180
7c673cae
FG
181 // m_append_separator_if_needed ----------------------------------------------------//
182
92f5a8d4 183 BOOST_FILESYSTEM_DECL path::string_type::size_type path::m_append_separator_if_needed()
7c673cae
FG
184 {
185 if (!m_pathname.empty() &&
186# ifdef BOOST_WINDOWS_API
92f5a8d4 187 *(m_pathname.end()-1) != colon &&
7c673cae 188# endif
b32b8144 189 !detail::is_directory_separator(*(m_pathname.end()-1)))
7c673cae
FG
190 {
191 string_type::size_type tmp(m_pathname.size());
192 m_pathname += preferred_separator;
193 return tmp;
194 }
195 return 0;
196 }
197
198 // m_erase_redundant_separator -----------------------------------------------------//
199
92f5a8d4 200 BOOST_FILESYSTEM_DECL void path::m_erase_redundant_separator(string_type::size_type sep_pos)
7c673cae
FG
201 {
202 if (sep_pos // a separator was added
203 && sep_pos < m_pathname.size() // and something was appended
204 && (m_pathname[sep_pos+1] == separator // and it was also separator
205# ifdef BOOST_WINDOWS_API
206 || m_pathname[sep_pos+1] == preferred_separator // or preferred_separator
207# endif
208)) { m_pathname.erase(sep_pos, 1); } // erase the added separator
209 }
210
211 // modifiers -----------------------------------------------------------------------//
212
213# ifdef BOOST_WINDOWS_API
92f5a8d4 214 BOOST_FILESYSTEM_DECL path& path::make_preferred()
7c673cae
FG
215 {
216 std::replace(m_pathname.begin(), m_pathname.end(), L'/', L'\\');
217 return *this;
218 }
219# endif
220
92f5a8d4 221 BOOST_FILESYSTEM_DECL path& path::remove_filename()
7c673cae
FG
222 {
223 m_pathname.erase(m_parent_path_end());
224 return *this;
225 }
226
92f5a8d4 227 BOOST_FILESYSTEM_DECL path& path::remove_trailing_separator()
7c673cae 228 {
b32b8144
FG
229 if (!m_pathname.empty()
230 && detail::is_directory_separator(m_pathname[m_pathname.size() - 1]))
7c673cae
FG
231 m_pathname.erase(m_pathname.size() - 1);
232 return *this;
233 }
234
92f5a8d4 235 BOOST_FILESYSTEM_DECL path& path::replace_extension(const path& new_extension)
7c673cae
FG
236 {
237 // erase existing extension, including the dot, if any
238 m_pathname.erase(m_pathname.size()-extension().m_pathname.size());
239
240 if (!new_extension.empty())
241 {
242 // append new_extension, adding the dot if necessary
243 if (new_extension.m_pathname[0] != dot)
244 m_pathname.push_back(dot);
245 m_pathname.append(new_extension.m_pathname);
246 }
247
248 return *this;
249 }
250
251 // decomposition -------------------------------------------------------------------//
252
92f5a8d4
TL
253 BOOST_FILESYSTEM_DECL path path::root_path() const
254 {
7c673cae
FG
255 path temp(root_name());
256 if (!root_directory().empty()) temp.m_pathname += root_directory().c_str();
257 return temp;
92f5a8d4 258 }
7c673cae 259
92f5a8d4 260 BOOST_FILESYSTEM_DECL path path::root_name() const
7c673cae
FG
261 {
262 iterator itr(begin());
263
264 return (itr.m_pos != m_pathname.size()
265 && (
266 (itr.m_element.m_pathname.size() > 1
b32b8144 267 && detail::is_directory_separator(itr.m_element.m_pathname[0])
92f5a8d4 268 && detail::is_directory_separator(itr.m_element.m_pathname[1]))
7c673cae 269# ifdef BOOST_WINDOWS_API
92f5a8d4 270 || itr.m_element.m_pathname[itr.m_element.m_pathname.size()-1] == colon
7c673cae 271# endif
92f5a8d4 272 ))
7c673cae
FG
273 ? itr.m_element
274 : path();
275 }
276
92f5a8d4 277 BOOST_FILESYSTEM_DECL path path::root_directory() const
7c673cae
FG
278 {
279 size_type pos(root_directory_start(m_pathname, m_pathname.size()));
280
281 return pos == string_type::npos
282 ? path()
283 : path(m_pathname.c_str() + pos, m_pathname.c_str() + pos + 1);
284 }
285
92f5a8d4 286 BOOST_FILESYSTEM_DECL path path::relative_path() const
7c673cae
FG
287 {
288 iterator itr(begin());
289
290 for (; itr.m_pos != m_pathname.size()
b32b8144 291 && (detail::is_directory_separator(itr.m_element.m_pathname[0])
7c673cae
FG
292# ifdef BOOST_WINDOWS_API
293 || itr.m_element.m_pathname[itr.m_element.m_pathname.size()-1] == colon
294# endif
295 ); ++itr) {}
296
297 return path(m_pathname.c_str() + itr.m_pos);
298 }
299
92f5a8d4 300 BOOST_FILESYSTEM_DECL string_type::size_type path::m_parent_path_end() const
7c673cae
FG
301 {
302 size_type end_pos(filename_pos(m_pathname, m_pathname.size()));
303
20effc67
TL
304 bool filename_was_separator = !m_pathname.empty()
305 && detail::is_directory_separator(m_pathname[end_pos]);
7c673cae
FG
306
307 // skip separators unless root directory
308 size_type root_dir_pos(root_directory_start(m_pathname, end_pos));
92f5a8d4 309 for (;
7c673cae
FG
310 end_pos > 0
311 && (end_pos-1) != root_dir_pos
b32b8144 312 && detail::is_directory_separator(m_pathname[end_pos-1])
7c673cae
FG
313 ;
314 --end_pos) {}
315
316 return (end_pos == 1 && root_dir_pos == 0 && filename_was_separator)
317 ? string_type::npos
318 : end_pos;
319 }
320
92f5a8d4 321 BOOST_FILESYSTEM_DECL path path::parent_path() const
7c673cae
FG
322 {
323 size_type end_pos(m_parent_path_end());
324 return end_pos == string_type::npos
325 ? path()
326 : path(m_pathname.c_str(), m_pathname.c_str() + end_pos);
327 }
328
92f5a8d4 329 BOOST_FILESYSTEM_DECL path path::filename() const
7c673cae
FG
330 {
331 size_type pos(filename_pos(m_pathname, m_pathname.size()));
20effc67 332 return (!m_pathname.empty()
7c673cae 333 && pos
b32b8144 334 && detail::is_directory_separator(m_pathname[pos])
7c673cae
FG
335 && !is_root_separator(m_pathname, pos))
336 ? detail::dot_path()
337 : path(m_pathname.c_str() + pos);
338 }
339
92f5a8d4 340 BOOST_FILESYSTEM_DECL path path::stem() const
7c673cae
FG
341 {
342 path name(filename());
343 if (name == detail::dot_path() || name == detail::dot_dot_path()) return name;
344 size_type pos(name.m_pathname.rfind(dot));
345 return pos == string_type::npos
346 ? name
347 : path(name.m_pathname.c_str(), name.m_pathname.c_str() + pos);
348 }
349
92f5a8d4 350 BOOST_FILESYSTEM_DECL path path::extension() const
7c673cae
FG
351 {
352 path name(filename());
353 if (name == detail::dot_path() || name == detail::dot_dot_path()) return path();
354 size_type pos(name.m_pathname.rfind(dot));
355 return pos == string_type::npos
356 ? path()
357 : path(name.m_pathname.c_str() + pos);
358 }
359
360 // lexical operations --------------------------------------------------------------//
361
362 namespace detail
363 {
92f5a8d4 364 // C++14 provides a mismatch algorithm with four iterator arguments(), but earlier
7c673cae
FG
365 // standard libraries didn't, so provide this needed functionality.
366 inline
367 std::pair<path::iterator, path::iterator> mismatch(path::iterator it1,
368 path::iterator it1end, path::iterator it2, path::iterator it2end)
369 {
370 for (; it1 != it1end && it2 != it2end && *it1 == *it2;)
371 {
372 ++it1;
373 ++it2;
374 }
375 return std::make_pair(it1, it2);
376 }
377 }
378
92f5a8d4 379 BOOST_FILESYSTEM_DECL path path::lexically_relative(const path& base) const
7c673cae 380 {
92f5a8d4
TL
381 path::iterator b = begin(), e = end(), base_b = base.begin(), base_e = base.end();
382 std::pair<path::iterator, path::iterator> mm = detail::mismatch(b, e, base_b, base_e);
383 if (mm.first == b && mm.second == base_b)
384 return path();
385 if (mm.first == e && mm.second == base_e)
386 return detail::dot_path();
387
388 std::ptrdiff_t n = 0;
389 for (; mm.second != base_e; ++mm.second)
390 {
391 path const& p = *mm.second;
392 if (p == detail::dot_dot_path())
393 --n;
394 else if (!p.empty() && p != detail::dot_path())
395 ++n;
396 }
397 if (n < 0)
7c673cae 398 return path();
92f5a8d4 399 if (n == 0 && (mm.first == e || mm.first->empty()))
7c673cae 400 return detail::dot_path();
92f5a8d4 401
7c673cae 402 path tmp;
92f5a8d4 403 for (; n > 0; --n)
7c673cae 404 tmp /= detail::dot_dot_path();
92f5a8d4 405 for (; mm.first != e; ++mm.first)
7c673cae
FG
406 tmp /= *mm.first;
407 return tmp;
408 }
409
410 // normal --------------------------------------------------------------------------//
411
92f5a8d4 412 BOOST_FILESYSTEM_DECL path path::lexically_normal() const
7c673cae
FG
413 {
414 if (m_pathname.empty())
415 return *this;
92f5a8d4 416
7c673cae
FG
417 path temp;
418 iterator start(begin());
419 iterator last(end());
420 iterator stop(last--);
421 for (iterator itr(start); itr != stop; ++itr)
422 {
423 // ignore "." except at start and last
424 if (itr->native().size() == 1
425 && (itr->native())[0] == dot
426 && itr != start
427 && itr != last) continue;
428
429 // ignore a name and following ".."
430 if (!temp.empty()
431 && itr->native().size() == 2
432 && (itr->native())[0] == dot
433 && (itr->native())[1] == dot) // dot dot
434 {
92f5a8d4 435 string_type lf(temp.filename().native());
20effc67
TL
436 string_type::size_type lf_size = lf.size();
437 if (lf_size > 0
438 && (lf_size != 1
7c673cae
FG
439 || (lf[0] != dot
440 && lf[0] != separator))
20effc67 441 && (lf_size != 2
7c673cae
FG
442 || (lf[0] != dot
443 && lf[1] != dot
444# ifdef BOOST_WINDOWS_API
445 && lf[1] != colon
446# endif
447 )
448 )
449 )
450 {
451 temp.remove_filename();
452 //// if not root directory, must also remove "/" if any
453 //if (temp.native().size() > 0
454 // && temp.native()[temp.native().size()-1]
455 // == separator)
456 //{
457 // string_type::size_type rds(
458 // root_directory_start(temp.native(), temp.native().size()));
459 // if (rds == string_type::npos
92f5a8d4 460 // || rds != temp.native().size()-1)
7c673cae
FG
461 // {
462 // temp.m_pathname.erase(temp.native().size()-1);
463 // }
464 //}
465
466 iterator next(itr);
467 if (temp.empty() && ++next != stop
468 && next == last && *last == detail::dot_path())
469 {
470 temp /= detail::dot_path();
471 }
472 continue;
473 }
474 }
475
476 temp /= *itr;
20effc67 477 }
7c673cae
FG
478
479 if (temp.empty())
480 temp /= detail::dot_path();
481 return temp;
482 }
483
484} // namespace filesystem
485} // namespace boost
92f5a8d4 486
7c673cae
FG
487//--------------------------------------------------------------------------------------//
488// //
489// class path helpers implementation //
490// //
491//--------------------------------------------------------------------------------------//
492
493namespace
494{
495
496 // is_root_separator ---------------------------------------------------------------//
497
498 bool is_root_separator(const string_type & str, size_type pos)
499 // pos is position of the separator
500 {
b32b8144 501 BOOST_ASSERT_MSG(!str.empty() && fs::detail::is_directory_separator(str[pos]),
7c673cae
FG
502 "precondition violation");
503
504 // subsequent logic expects pos to be for leftmost slash of a set
b32b8144 505 while (pos > 0 && fs::detail::is_directory_separator(str[pos-1]))
7c673cae
FG
506 --pos;
507
508 // "/" [...]
92f5a8d4 509 if (pos == 0)
7c673cae
FG
510 return true;
511
512# ifdef BOOST_WINDOWS_API
513 // "c:/" [...]
92f5a8d4 514 if (pos == 2 && is_letter(str[0]) && str[1] == colon)
7c673cae
FG
515 return true;
516# endif
517
518 // "//" name "/"
b32b8144
FG
519 if (pos < 3 || !fs::detail::is_directory_separator(str[0])
520 || !fs::detail::is_directory_separator(str[1]))
7c673cae
FG
521 return false;
522
523 return str.find_first_of(separators, 2) == pos;
524 }
525
526 // filename_pos --------------------------------------------------------------------//
527
528 size_type filename_pos(const string_type & str,
529 size_type end_pos) // end_pos is past-the-end position
530 // return 0 if str itself is filename (or empty)
531 {
532 // case: "//"
92f5a8d4 533 if (end_pos == 2
b32b8144
FG
534 && fs::detail::is_directory_separator(str[0])
535 && fs::detail::is_directory_separator(str[1])) return 0;
7c673cae
FG
536
537 // case: ends in "/"
b32b8144 538 if (end_pos && fs::detail::is_directory_separator(str[end_pos-1]))
7c673cae 539 return end_pos-1;
92f5a8d4 540
7c673cae
FG
541 // set pos to start of last element
542 size_type pos(str.find_last_of(separators, end_pos-1));
543
544# ifdef BOOST_WINDOWS_API
545 if (pos == string_type::npos && end_pos > 1)
546 pos = str.find_last_of(colon, end_pos-2);
547# endif
548
549 return (pos == string_type::npos // path itself must be a filename (or empty)
b32b8144 550 || (pos == 1 && fs::detail::is_directory_separator(str[0]))) // or net
7c673cae
FG
551 ? 0 // so filename is entire string
552 : pos + 1; // or starts after delimiter
553 }
554
555 // root_directory_start ------------------------------------------------------------//
556
557 size_type root_directory_start(const string_type & path, size_type size)
558 // return npos if no root_directory found
559 {
560
561# ifdef BOOST_WINDOWS_API
562 // case "c:/"
563 if (size > 2
564 && path[1] == colon
b32b8144 565 && fs::detail::is_directory_separator(path[2])) return 2;
7c673cae
FG
566# endif
567
568 // case "//"
569 if (size == 2
b32b8144
FG
570 && fs::detail::is_directory_separator(path[0])
571 && fs::detail::is_directory_separator(path[1])) return string_type::npos;
7c673cae
FG
572
573# ifdef BOOST_WINDOWS_API
574 // case "\\?\"
575 if (size > 4
b32b8144
FG
576 && fs::detail::is_directory_separator(path[0])
577 && fs::detail::is_directory_separator(path[1])
7c673cae 578 && path[2] == questionmark
b32b8144 579 && fs::detail::is_directory_separator(path[3]))
7c673cae
FG
580 {
581 string_type::size_type pos(path.find_first_of(separators, 4));
582 return pos < size ? pos : string_type::npos;
583 }
584# endif
585
586 // case "//net {/}"
587 if (size > 3
b32b8144
FG
588 && fs::detail::is_directory_separator(path[0])
589 && fs::detail::is_directory_separator(path[1])
590 && !fs::detail::is_directory_separator(path[2]))
7c673cae
FG
591 {
592 string_type::size_type pos(path.find_first_of(separators, 2));
593 return pos < size ? pos : string_type::npos;
594 }
92f5a8d4 595
7c673cae 596 // case "/"
b32b8144 597 if (size > 0 && fs::detail::is_directory_separator(path[0])) return 0;
7c673cae
FG
598
599 return string_type::npos;
600 }
601
602 // first_element --------------------------------------------------------------------//
603 // sets pos and len of first element, excluding extra separators
604 // if src.empty(), sets pos,len, to 0,0.
605
606 void first_element(
607 const string_type & src,
608 size_type & element_pos,
609 size_type & element_size,
610 size_type size
20effc67 611 )
7c673cae
FG
612 {
613 if (size == string_type::npos) size = src.size();
614 element_pos = 0;
615 element_size = 0;
616 if (src.empty()) return;
617
618 string_type::size_type cur(0);
92f5a8d4 619
7c673cae 620 // deal with // [network]
b32b8144
FG
621 if (size >= 2 && fs::detail::is_directory_separator(src[0])
622 && fs::detail::is_directory_separator(src[1])
7c673cae 623 && (size == 2
b32b8144 624 || !fs::detail::is_directory_separator(src[2])))
92f5a8d4 625 {
7c673cae
FG
626 cur += 2;
627 element_size += 2;
628 }
629
630 // leading (not non-network) separator
b32b8144 631 else if (fs::detail::is_directory_separator(src[0]))
7c673cae
FG
632 {
633 ++element_size;
634 // bypass extra leading separators
635 while (cur+1 < size
b32b8144 636 && fs::detail::is_directory_separator(src[cur+1]))
7c673cae
FG
637 {
638 ++cur;
639 ++element_pos;
640 }
641 return;
642 }
643
644 // at this point, we have either a plain name, a network name,
645 // or (on Windows only) a device name
646
647 // find the end
648 while (cur < size
649# ifdef BOOST_WINDOWS_API
650 && src[cur] != colon
651# endif
b32b8144 652 && !fs::detail::is_directory_separator(src[cur]))
7c673cae
FG
653 {
654 ++cur;
655 ++element_size;
656 }
657
658# ifdef BOOST_WINDOWS_API
659 if (cur == size) return;
660 // include device delimiter
661 if (src[cur] == colon)
662 { ++element_size; }
663# endif
7c673cae
FG
664 }
665
666} // unnamed namespace
667
668
669namespace boost
670{
671namespace filesystem
672{
673 namespace detail
674 {
675 BOOST_FILESYSTEM_DECL
92f5a8d4 676 int lex_compare(path::iterator first1, path::iterator last1,
7c673cae
FG
677 path::iterator first2, path::iterator last2)
678 {
679 for (; first1 != last1 && first2 != last2;)
680 {
681 if (first1->native() < first2->native()) return -1;
682 if (first2->native() < first1->native()) return 1;
683 BOOST_ASSERT(first2->native() == first1->native());
684 ++first1;
685 ++first2;
686 }
687 if (first1 == last1 && first2 == last2)
688 return 0;
689 return first1 == last1 ? -1 : 1;
690 }
691
692 BOOST_FILESYSTEM_DECL
693 const path& dot_path()
694 {
695# ifdef BOOST_WINDOWS_API
696 static const fs::path dot_pth(L".");
697# else
698 static const fs::path dot_pth(".");
699# endif
700 return dot_pth;
701 }
702
703 BOOST_FILESYSTEM_DECL
704 const path& dot_dot_path()
705 {
706# ifdef BOOST_WINDOWS_API
707 static const fs::path dot_dot(L"..");
708# else
709 static const fs::path dot_dot("..");
710# endif
711 return dot_dot;
712 }
713 }
714
715//--------------------------------------------------------------------------------------//
716// //
717// class path::iterator implementation //
718// //
719//--------------------------------------------------------------------------------------//
720
92f5a8d4 721 BOOST_FILESYSTEM_DECL path::iterator path::begin() const
7c673cae
FG
722 {
723 iterator itr;
724 itr.m_path_ptr = this;
725 size_type element_size;
726 first_element(m_pathname, itr.m_pos, element_size);
727 itr.m_element = m_pathname.substr(itr.m_pos, element_size);
728 if (itr.m_element.m_pathname == preferred_separator_string)
729 itr.m_element.m_pathname = separator_string; // needed for Windows, harmless on POSIX
730 return itr;
731 }
732
92f5a8d4 733 BOOST_FILESYSTEM_DECL path::iterator path::end() const
7c673cae
FG
734 {
735 iterator itr;
736 itr.m_path_ptr = this;
737 itr.m_pos = m_pathname.size();
738 return itr;
739 }
740
92f5a8d4 741 BOOST_FILESYSTEM_DECL void path::m_path_iterator_increment(path::iterator & it)
7c673cae
FG
742 {
743 BOOST_ASSERT_MSG(it.m_pos < it.m_path_ptr->m_pathname.size(),
744 "path::basic_iterator increment past end()");
745
746 // increment to position past current element; if current element is implicit dot,
747 // this will cause it.m_pos to represent the end iterator
748 it.m_pos += it.m_element.m_pathname.size();
749
750 // if the end is reached, we are done
751 if (it.m_pos == it.m_path_ptr->m_pathname.size())
752 {
753 it.m_element.clear(); // aids debugging, may release unneeded memory
754 return;
755 }
756
757 // both POSIX and Windows treat paths that begin with exactly two separators specially
758 bool was_net(it.m_element.m_pathname.size() > 2
b32b8144
FG
759 && detail::is_directory_separator(it.m_element.m_pathname[0])
760 && detail::is_directory_separator(it.m_element.m_pathname[1])
761 && !detail::is_directory_separator(it.m_element.m_pathname[2]));
7c673cae
FG
762
763 // process separator (Windows drive spec is only case not a separator)
b32b8144 764 if (detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos]))
7c673cae
FG
765 {
766 // detect root directory
767 if (was_net
768# ifdef BOOST_WINDOWS_API
769 // case "c:/"
770 || it.m_element.m_pathname[it.m_element.m_pathname.size()-1] == colon
771# endif
772 )
773 {
774 it.m_element.m_pathname = separator; // generic format; see docs
775 return;
776 }
777
778 // skip separators until it.m_pos points to the start of the next element
779 while (it.m_pos != it.m_path_ptr->m_pathname.size()
b32b8144 780 && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos]))
7c673cae
FG
781 { ++it.m_pos; }
782
783 // detect trailing separator, and treat it as ".", per POSIX spec
784 if (it.m_pos == it.m_path_ptr->m_pathname.size()
92f5a8d4 785 && !is_root_separator(it.m_path_ptr->m_pathname, it.m_pos-1))
7c673cae
FG
786 {
787 --it.m_pos;
788 it.m_element = detail::dot_path();
789 return;
790 }
791 }
792
793 // get m_element
794 size_type end_pos(it.m_path_ptr->m_pathname.find_first_of(separators, it.m_pos));
795 if (end_pos == string_type::npos)
796 end_pos = it.m_path_ptr->m_pathname.size();
797 it.m_element = it.m_path_ptr->m_pathname.substr(it.m_pos, end_pos - it.m_pos);
798 }
799
92f5a8d4 800 BOOST_FILESYSTEM_DECL void path::m_path_iterator_decrement(path::iterator & it)
7c673cae
FG
801 {
802 BOOST_ASSERT_MSG(it.m_pos, "path::iterator decrement past begin()");
803
804 size_type end_pos(it.m_pos);
805
806 // if at end and there was a trailing non-root '/', return "."
807 if (it.m_pos == it.m_path_ptr->m_pathname.size()
808 && it.m_path_ptr->m_pathname.size() > 1
b32b8144 809 && detail::is_directory_separator(it.m_path_ptr->m_pathname[it.m_pos-1])
92f5a8d4 810 && !is_root_separator(it.m_path_ptr->m_pathname, it.m_pos-1)
7c673cae
FG
811 )
812 {
813 --it.m_pos;
814 it.m_element = detail::dot_path();
815 return;
816 }
817
818 size_type root_dir_pos(root_directory_start(it.m_path_ptr->m_pathname, end_pos));
819
820 // skip separators unless root directory
821 for (
92f5a8d4 822 ;
7c673cae
FG
823 end_pos > 0
824 && (end_pos-1) != root_dir_pos
b32b8144 825 && detail::is_directory_separator(it.m_path_ptr->m_pathname[end_pos-1])
7c673cae
FG
826 ;
827 --end_pos) {}
828
829 it.m_pos = filename_pos(it.m_path_ptr->m_pathname, end_pos);
830 it.m_element = it.m_path_ptr->m_pathname.substr(it.m_pos, end_pos - it.m_pos);
92f5a8d4
TL
831 if (it.m_element.m_pathname == preferred_separator_string) // needed for Windows, harmless on POSIX
832 it.m_element.m_pathname = separator_string; // generic format; see docs
7c673cae
FG
833 }
834
835} // namespace filesystem
836} // namespace boost
837
838namespace
839{
840
841 //------------------------------------------------------------------------------------//
842 // locale helpers //
843 //------------------------------------------------------------------------------------//
844
845 // Prior versions of these locale and codecvt implementations tried to take advantage
846 // of static initialization where possible, kept a local copy of the current codecvt
847 // facet (to avoid codecvt() having to call use_facet()), and was not multi-threading
848 // safe (again for efficiency).
849 //
850 // This was error prone, and required different implementation techniques depending
851 // on the compiler and also whether static or dynamic linking was used. Furthermore,
852 // users could not easily provide their multi-threading safe wrappers because the
853 // path interface requires the implementation itself to call codecvt() to obtain the
854 // default facet, and the initialization of the static within path_locale() could race.
855 //
92f5a8d4 856 // The code below is portable to all platforms, is much simpler, and hopefully will be
7c673cae
FG
857 // much more robust. Timing tests (on Windows, using a Visual C++ release build)
858 // indicated the current code is roughly 9% slower than the previous code, and that
92f5a8d4 859 // seems a small price to pay for better code that is easier to use.
7c673cae
FG
860
861 std::locale default_locale()
862 {
863# if defined(BOOST_WINDOWS_API)
864 std::locale global_loc = std::locale();
865 return std::locale(global_loc, new windows_file_codecvt);
866# elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \
867 || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
868 // "All BSD system functions expect their string parameters to be in UTF-8 encoding
869 // and nothing else." See
870 // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html
871 //
872 // "The kernel will reject any filename that is not a valid UTF-8 string, and it will
873 // even be normalized (to Unicode NFD) before stored on disk, at least when using HFS.
874 // The right way to deal with it would be to always convert the filename to UTF-8
875 // before trying to open/create a file." See
876 // http://lists.apple.com/archives/unix-porting/2007/Sep/msg00023.html
877 //
878 // "How a file name looks at the API level depends on the API. Current Carbon APIs
879 // handle file names as an array of UTF-16 characters; POSIX ones handle them as an
880 // array of UTF-8, which is why UTF-8 works well in Terminal. How it's stored on disk
881 // depends on the disk format; HFS+ uses UTF-16, but that's not important in most
882 // cases." See
883 // http://lists.apple.com/archives/applescript-users/2002/Sep/msg00319.html
884 //
885 // Many thanks to Peter Dimov for digging out the above references!
886
887 std::locale global_loc = std::locale();
888 return std::locale(global_loc, new boost::filesystem::detail::utf8_codecvt_facet);
889# else // Other POSIX
890 // ISO C calls std::locale("") "the locale-specific native environment", and this
891 // locale is the default for many POSIX-based operating systems such as Linux.
892 return std::locale("");
893# endif
894 }
895
896 std::locale& path_locale()
897 // std::locale("") construction, needed on non-Apple POSIX systems, can throw
898 // (if environmental variables LC_MESSAGES or LANG are wrong, for example), so
92f5a8d4 899 // path_locale() provides lazy initialization via a local static to ensure that any
7c673cae
FG
900 // exceptions occur after main() starts and so can be caught. Furthermore,
901 // path_locale() is only called if path::codecvt() or path::imbue() are themselves
902 // actually called, ensuring that an exception will only be thrown if std::locale("")
903 // is really needed.
904 {
905 // [locale] paragraph 6: Once a facet reference is obtained from a locale object by
906 // calling use_facet<>, that reference remains usable, and the results from member
907 // functions of it may be cached and re-used, as long as some locale object refers
908 // to that facet.
909 static std::locale loc(default_locale());
910#ifdef BOOST_FILESYSTEM_DEBUG
911 std::cout << "***** path_locale() called" << std::endl;
912#endif
913 return loc;
914 }
915} // unnamed namespace
916
917//--------------------------------------------------------------------------------------//
918// path::codecvt() and path::imbue() implementation //
919//--------------------------------------------------------------------------------------//
920
921namespace boost
922{
923namespace filesystem
924{
925 // See comments above
926
92f5a8d4 927 BOOST_FILESYSTEM_DECL const path::codecvt_type& path::codecvt()
7c673cae
FG
928 {
929#ifdef BOOST_FILESYSTEM_DEBUG
930 std::cout << "***** path::codecvt() called" << std::endl;
931#endif
932 BOOST_ASSERT_MSG(&path_locale(), "boost::filesystem::path locale initialization error");
933
934 return std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t> >(path_locale());
935 }
936
92f5a8d4 937 BOOST_FILESYSTEM_DECL std::locale path::imbue(const std::locale& loc)
7c673cae
FG
938 {
939#ifdef BOOST_FILESYSTEM_DEBUG
940 std::cout << "***** path::imbue() called" << std::endl;
941#endif
942 std::locale temp(path_locale());
943 path_locale() = loc;
944 return temp;
945 }
946
947} // namespace filesystem
948} // namespace boost