1 // filesystem path.cpp ------------------------------------------------------------- //
3 // Copyright Beman Dawes 2008
5 // Distributed under the Boost Software License, Version 1.0.
6 // See http://www.boost.org/LICENSE_1_0.txt
8 // Library home page: http://www.boost.org/libs/filesystem
10 // Include Boost.Predef first so that windows.h is guaranteed to be not included
11 #include <boost/predef/os/windows.h>
13 #include <boost/winapi/config.hpp>
16 // Old standard library configurations, particularly MingGW, don't support wide strings.
17 // Report this with an explicit error message.
18 #include <boost/config.hpp>
19 # if defined( BOOST_NO_STD_WSTRING )
20 # error Configuration not supported: Boost.Filesystem V3 and later requires std::wstring support
23 #ifndef BOOST_SYSTEM_NO_DEPRECATED
24 # define BOOST_SYSTEM_NO_DEPRECATED
27 #include <boost/filesystem/config.hpp>
28 #include <boost/filesystem/path.hpp>
29 #include <boost/filesystem/operations.hpp> // for filesystem_error
30 #include <boost/scoped_array.hpp>
31 #include <boost/system/error_code.hpp>
32 #include <boost/assert.hpp>
40 #ifdef BOOST_WINDOWS_API
41 # include "windows_file_codecvt.hpp"
43 #elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \
44 || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
45 # include <boost/filesystem/detail/utf8_codecvt_facet.hpp>
48 #ifdef BOOST_FILESYSTEM_DEBUG
53 namespace fs
= boost::filesystem
;
55 using boost::filesystem::path
;
60 using boost::system::error_code
;
62 //--------------------------------------------------------------------------------------//
64 // class path helpers //
66 //--------------------------------------------------------------------------------------//
70 //------------------------------------------------------------------------------------//
71 // miscellaneous class path helpers //
72 //------------------------------------------------------------------------------------//
74 typedef path::value_type value_type
;
75 typedef path::string_type string_type
;
76 typedef string_type::size_type size_type
;
78 # ifdef BOOST_WINDOWS_API
80 const wchar_t* const separators
= L
"/\\";
81 const wchar_t* separator_string
= L
"/";
82 const wchar_t* preferred_separator_string
= L
"\\";
83 const wchar_t colon
= L
':';
84 const wchar_t questionmark
= L
'?';
86 inline bool is_letter(wchar_t c
)
88 return (c
>= L
'a' && c
<=L
'z') || (c
>= L
'A' && c
<=L
'Z');
93 const char* const separators
= "/";
94 const char* separator_string
= "/";
95 const char* preferred_separator_string
= "/";
99 bool is_root_separator(const string_type
& str
, size_type pos
);
100 // pos is position of the separator
102 size_type
filename_pos(const string_type
& str
,
103 size_type end_pos
); // end_pos is past-the-end position
104 // Returns: 0 if str itself is filename (or empty)
106 size_type
root_directory_start(const string_type
& path
, size_type size
);
107 // Returns: npos if no root_directory found
110 const string_type
& src
,
111 size_type
& element_pos
,
112 size_type
& element_size
,
113 # if !BOOST_WORKAROUND(BOOST_MSVC, <= 1310) // VC++ 7.1
114 size_type size
= string_type::npos
120 } // unnamed namespace
122 //--------------------------------------------------------------------------------------//
124 // class path implementation //
126 //--------------------------------------------------------------------------------------//
133 BOOST_FILESYSTEM_DECL path
& path::operator/=(const path
& p
)
137 if (this == &p
) // self-append
140 if (!detail::is_directory_separator(rhs
.m_pathname
[0]))
141 m_append_separator_if_needed();
142 m_pathname
+= rhs
.m_pathname
;
146 if (!detail::is_directory_separator(*p
.m_pathname
.begin()))
147 m_append_separator_if_needed();
148 m_pathname
+= p
.m_pathname
;
153 BOOST_FILESYSTEM_DECL path
& path::operator/=(const value_type
* ptr
)
157 if (ptr
>= m_pathname
.data()
158 && ptr
< m_pathname
.data() + m_pathname
.size()) // overlapping source
161 if (!detail::is_directory_separator(rhs
.m_pathname
[0]))
162 m_append_separator_if_needed();
163 m_pathname
+= rhs
.m_pathname
;
167 if (!detail::is_directory_separator(*ptr
))
168 m_append_separator_if_needed();
174 # ifdef BOOST_WINDOWS_API
176 BOOST_FILESYSTEM_DECL path
path::generic_path() const
179 std::replace(tmp
.m_pathname
.begin(), tmp
.m_pathname
.end(), L
'\\', L
'/');
183 # endif // BOOST_WINDOWS_API
185 BOOST_FILESYSTEM_DECL
int path::compare(const path
& p
) const BOOST_NOEXCEPT
187 return detail::lex_compare(begin(), end(), p
.begin(), p
.end());
190 // m_append_separator_if_needed ----------------------------------------------------//
192 BOOST_FILESYSTEM_DECL
path::string_type::size_type
path::m_append_separator_if_needed()
194 if (!m_pathname
.empty() &&
195 # ifdef BOOST_WINDOWS_API
196 *(m_pathname
.end()-1) != colon
&&
198 !detail::is_directory_separator(*(m_pathname
.end()-1)))
200 string_type::size_type
tmp(m_pathname
.size());
201 m_pathname
+= preferred_separator
;
207 // m_erase_redundant_separator -----------------------------------------------------//
209 BOOST_FILESYSTEM_DECL
void path::m_erase_redundant_separator(string_type::size_type sep_pos
)
211 if (sep_pos
// a separator was added
212 && sep_pos
< m_pathname
.size() // and something was appended
213 && (m_pathname
[sep_pos
+1] == separator
// and it was also separator
214 # ifdef BOOST_WINDOWS_API
215 || m_pathname
[sep_pos
+1] == preferred_separator
// or preferred_separator
217 )) { m_pathname
.erase(sep_pos
, 1); } // erase the added separator
220 // modifiers -----------------------------------------------------------------------//
222 # ifdef BOOST_WINDOWS_API
223 BOOST_FILESYSTEM_DECL path
& path::make_preferred()
225 std::replace(m_pathname
.begin(), m_pathname
.end(), L
'/', L
'\\');
230 BOOST_FILESYSTEM_DECL path
& path::remove_filename()
232 m_pathname
.erase(m_parent_path_end());
236 BOOST_FILESYSTEM_DECL path
& path::remove_trailing_separator()
238 if (!m_pathname
.empty()
239 && detail::is_directory_separator(m_pathname
[m_pathname
.size() - 1]))
240 m_pathname
.erase(m_pathname
.size() - 1);
244 BOOST_FILESYSTEM_DECL path
& path::replace_extension(const path
& new_extension
)
246 // erase existing extension, including the dot, if any
247 m_pathname
.erase(m_pathname
.size()-extension().m_pathname
.size());
249 if (!new_extension
.empty())
251 // append new_extension, adding the dot if necessary
252 if (new_extension
.m_pathname
[0] != dot
)
253 m_pathname
.push_back(dot
);
254 m_pathname
.append(new_extension
.m_pathname
);
260 // decomposition -------------------------------------------------------------------//
262 BOOST_FILESYSTEM_DECL path
path::root_path() const
264 path
temp(root_name());
265 if (!root_directory().empty()) temp
.m_pathname
+= root_directory().c_str();
269 BOOST_FILESYSTEM_DECL path
path::root_name() const
271 iterator
itr(begin());
273 return (itr
.m_pos
!= m_pathname
.size()
275 (itr
.m_element
.m_pathname
.size() > 1
276 && detail::is_directory_separator(itr
.m_element
.m_pathname
[0])
277 && detail::is_directory_separator(itr
.m_element
.m_pathname
[1]))
278 # ifdef BOOST_WINDOWS_API
279 || itr
.m_element
.m_pathname
[itr
.m_element
.m_pathname
.size()-1] == colon
286 BOOST_FILESYSTEM_DECL path
path::root_directory() const
288 size_type
pos(root_directory_start(m_pathname
, m_pathname
.size()));
290 return pos
== string_type::npos
292 : path(m_pathname
.c_str() + pos
, m_pathname
.c_str() + pos
+ 1);
295 BOOST_FILESYSTEM_DECL path
path::relative_path() const
297 iterator
itr(begin());
299 for (; itr
.m_pos
!= m_pathname
.size()
300 && (detail::is_directory_separator(itr
.m_element
.m_pathname
[0])
301 # ifdef BOOST_WINDOWS_API
302 || itr
.m_element
.m_pathname
[itr
.m_element
.m_pathname
.size()-1] == colon
306 return path(m_pathname
.c_str() + itr
.m_pos
);
309 BOOST_FILESYSTEM_DECL
string_type::size_type
path::m_parent_path_end() const
311 size_type
end_pos(filename_pos(m_pathname
, m_pathname
.size()));
313 bool filename_was_separator(m_pathname
.size()
314 && detail::is_directory_separator(m_pathname
[end_pos
]));
316 // skip separators unless root directory
317 size_type
root_dir_pos(root_directory_start(m_pathname
, end_pos
));
320 && (end_pos
-1) != root_dir_pos
321 && detail::is_directory_separator(m_pathname
[end_pos
-1])
325 return (end_pos
== 1 && root_dir_pos
== 0 && filename_was_separator
)
330 BOOST_FILESYSTEM_DECL path
path::parent_path() const
332 size_type
end_pos(m_parent_path_end());
333 return end_pos
== string_type::npos
335 : path(m_pathname
.c_str(), m_pathname
.c_str() + end_pos
);
338 BOOST_FILESYSTEM_DECL path
path::filename() const
340 size_type
pos(filename_pos(m_pathname
, m_pathname
.size()));
341 return (m_pathname
.size()
343 && detail::is_directory_separator(m_pathname
[pos
])
344 && !is_root_separator(m_pathname
, pos
))
346 : path(m_pathname
.c_str() + pos
);
349 BOOST_FILESYSTEM_DECL path
path::stem() const
351 path
name(filename());
352 if (name
== detail::dot_path() || name
== detail::dot_dot_path()) return name
;
353 size_type
pos(name
.m_pathname
.rfind(dot
));
354 return pos
== string_type::npos
356 : path(name
.m_pathname
.c_str(), name
.m_pathname
.c_str() + pos
);
359 BOOST_FILESYSTEM_DECL path
path::extension() const
361 path
name(filename());
362 if (name
== detail::dot_path() || name
== detail::dot_dot_path()) return path();
363 size_type
pos(name
.m_pathname
.rfind(dot
));
364 return pos
== string_type::npos
366 : path(name
.m_pathname
.c_str() + pos
);
369 // lexical operations --------------------------------------------------------------//
373 // C++14 provides a mismatch algorithm with four iterator arguments(), but earlier
374 // standard libraries didn't, so provide this needed functionality.
376 std::pair
<path::iterator
, path::iterator
> mismatch(path::iterator it1
,
377 path::iterator it1end
, path::iterator it2
, path::iterator it2end
)
379 for (; it1
!= it1end
&& it2
!= it2end
&& *it1
== *it2
;)
384 return std::make_pair(it1
, it2
);
388 BOOST_FILESYSTEM_DECL path
path::lexically_relative(const path
& base
) const
390 path::iterator b
= begin(), e
= end(), base_b
= base
.begin(), base_e
= base
.end();
391 std::pair
<path::iterator
, path::iterator
> mm
= detail::mismatch(b
, e
, base_b
, base_e
);
392 if (mm
.first
== b
&& mm
.second
== base_b
)
394 if (mm
.first
== e
&& mm
.second
== base_e
)
395 return detail::dot_path();
397 std::ptrdiff_t n
= 0;
398 for (; mm
.second
!= base_e
; ++mm
.second
)
400 path
const& p
= *mm
.second
;
401 if (p
== detail::dot_dot_path())
403 else if (!p
.empty() && p
!= detail::dot_path())
408 if (n
== 0 && (mm
.first
== e
|| mm
.first
->empty()))
409 return detail::dot_path();
413 tmp
/= detail::dot_dot_path();
414 for (; mm
.first
!= e
; ++mm
.first
)
419 // normal --------------------------------------------------------------------------//
421 BOOST_FILESYSTEM_DECL path
path::lexically_normal() const
423 if (m_pathname
.empty())
427 iterator
start(begin());
428 iterator
last(end());
429 iterator
stop(last
--);
430 for (iterator
itr(start
); itr
!= stop
; ++itr
)
432 // ignore "." except at start and last
433 if (itr
->native().size() == 1
434 && (itr
->native())[0] == dot
436 && itr
!= last
) continue;
438 // ignore a name and following ".."
440 && itr
->native().size() == 2
441 && (itr
->native())[0] == dot
442 && (itr
->native())[1] == dot
) // dot dot
444 string_type
lf(temp
.filename().native());
448 && lf
[0] != separator
))
452 # ifdef BOOST_WINDOWS_API
459 temp
.remove_filename();
460 //// if not root directory, must also remove "/" if any
461 //if (temp.native().size() > 0
462 // && temp.native()[temp.native().size()-1]
465 // string_type::size_type rds(
466 // root_directory_start(temp.native(), temp.native().size()));
467 // if (rds == string_type::npos
468 // || rds != temp.native().size()-1)
470 // temp.m_pathname.erase(temp.native().size()-1);
475 if (temp
.empty() && ++next
!= stop
476 && next
== last
&& *last
== detail::dot_path())
478 temp
/= detail::dot_path();
488 temp
/= detail::dot_path();
492 } // namespace filesystem
495 //--------------------------------------------------------------------------------------//
497 // class path helpers implementation //
499 //--------------------------------------------------------------------------------------//
504 // is_root_separator ---------------------------------------------------------------//
506 bool is_root_separator(const string_type
& str
, size_type pos
)
507 // pos is position of the separator
509 BOOST_ASSERT_MSG(!str
.empty() && fs::detail::is_directory_separator(str
[pos
]),
510 "precondition violation");
512 // subsequent logic expects pos to be for leftmost slash of a set
513 while (pos
> 0 && fs::detail::is_directory_separator(str
[pos
-1]))
520 # ifdef BOOST_WINDOWS_API
522 if (pos
== 2 && is_letter(str
[0]) && str
[1] == colon
)
527 if (pos
< 3 || !fs::detail::is_directory_separator(str
[0])
528 || !fs::detail::is_directory_separator(str
[1]))
531 return str
.find_first_of(separators
, 2) == pos
;
534 // filename_pos --------------------------------------------------------------------//
536 size_type
filename_pos(const string_type
& str
,
537 size_type end_pos
) // end_pos is past-the-end position
538 // return 0 if str itself is filename (or empty)
542 && fs::detail::is_directory_separator(str
[0])
543 && fs::detail::is_directory_separator(str
[1])) return 0;
546 if (end_pos
&& fs::detail::is_directory_separator(str
[end_pos
-1]))
549 // set pos to start of last element
550 size_type
pos(str
.find_last_of(separators
, end_pos
-1));
552 # ifdef BOOST_WINDOWS_API
553 if (pos
== string_type::npos
&& end_pos
> 1)
554 pos
= str
.find_last_of(colon
, end_pos
-2);
557 return (pos
== string_type::npos
// path itself must be a filename (or empty)
558 || (pos
== 1 && fs::detail::is_directory_separator(str
[0]))) // or net
559 ? 0 // so filename is entire string
560 : pos
+ 1; // or starts after delimiter
563 // root_directory_start ------------------------------------------------------------//
565 size_type
root_directory_start(const string_type
& path
, size_type size
)
566 // return npos if no root_directory found
569 # ifdef BOOST_WINDOWS_API
573 && fs::detail::is_directory_separator(path
[2])) return 2;
578 && fs::detail::is_directory_separator(path
[0])
579 && fs::detail::is_directory_separator(path
[1])) return string_type::npos
;
581 # ifdef BOOST_WINDOWS_API
584 && fs::detail::is_directory_separator(path
[0])
585 && fs::detail::is_directory_separator(path
[1])
586 && path
[2] == questionmark
587 && fs::detail::is_directory_separator(path
[3]))
589 string_type::size_type
pos(path
.find_first_of(separators
, 4));
590 return pos
< size
? pos
: string_type::npos
;
596 && fs::detail::is_directory_separator(path
[0])
597 && fs::detail::is_directory_separator(path
[1])
598 && !fs::detail::is_directory_separator(path
[2]))
600 string_type::size_type
pos(path
.find_first_of(separators
, 2));
601 return pos
< size
? pos
: string_type::npos
;
605 if (size
> 0 && fs::detail::is_directory_separator(path
[0])) return 0;
607 return string_type::npos
;
610 // first_element --------------------------------------------------------------------//
611 // sets pos and len of first element, excluding extra separators
612 // if src.empty(), sets pos,len, to 0,0.
615 const string_type
& src
,
616 size_type
& element_pos
,
617 size_type
& element_size
,
621 if (size
== string_type::npos
) size
= src
.size();
624 if (src
.empty()) return;
626 string_type::size_type
cur(0);
628 // deal with // [network]
629 if (size
>= 2 && fs::detail::is_directory_separator(src
[0])
630 && fs::detail::is_directory_separator(src
[1])
632 || !fs::detail::is_directory_separator(src
[2])))
638 // leading (not non-network) separator
639 else if (fs::detail::is_directory_separator(src
[0]))
642 // bypass extra leading separators
644 && fs::detail::is_directory_separator(src
[cur
+1]))
652 // at this point, we have either a plain name, a network name,
653 // or (on Windows only) a device name
657 # ifdef BOOST_WINDOWS_API
660 && !fs::detail::is_directory_separator(src
[cur
]))
666 # ifdef BOOST_WINDOWS_API
667 if (cur
== size
) return;
668 // include device delimiter
669 if (src
[cur
] == colon
)
676 } // unnamed namespace
685 BOOST_FILESYSTEM_DECL
686 int lex_compare(path::iterator first1
, path::iterator last1
,
687 path::iterator first2
, path::iterator last2
)
689 for (; first1
!= last1
&& first2
!= last2
;)
691 if (first1
->native() < first2
->native()) return -1;
692 if (first2
->native() < first1
->native()) return 1;
693 BOOST_ASSERT(first2
->native() == first1
->native());
697 if (first1
== last1
&& first2
== last2
)
699 return first1
== last1
? -1 : 1;
702 BOOST_FILESYSTEM_DECL
703 const path
& dot_path()
705 # ifdef BOOST_WINDOWS_API
706 static const fs::path
dot_pth(L
".");
708 static const fs::path
dot_pth(".");
713 BOOST_FILESYSTEM_DECL
714 const path
& dot_dot_path()
716 # ifdef BOOST_WINDOWS_API
717 static const fs::path
dot_dot(L
"..");
719 static const fs::path
dot_dot("..");
725 //--------------------------------------------------------------------------------------//
727 // class path::iterator implementation //
729 //--------------------------------------------------------------------------------------//
731 BOOST_FILESYSTEM_DECL
path::iterator
path::begin() const
734 itr
.m_path_ptr
= this;
735 size_type element_size
;
736 first_element(m_pathname
, itr
.m_pos
, element_size
);
737 itr
.m_element
= m_pathname
.substr(itr
.m_pos
, element_size
);
738 if (itr
.m_element
.m_pathname
== preferred_separator_string
)
739 itr
.m_element
.m_pathname
= separator_string
; // needed for Windows, harmless on POSIX
743 BOOST_FILESYSTEM_DECL
path::iterator
path::end() const
746 itr
.m_path_ptr
= this;
747 itr
.m_pos
= m_pathname
.size();
751 BOOST_FILESYSTEM_DECL
void path::m_path_iterator_increment(path::iterator
& it
)
753 BOOST_ASSERT_MSG(it
.m_pos
< it
.m_path_ptr
->m_pathname
.size(),
754 "path::basic_iterator increment past end()");
756 // increment to position past current element; if current element is implicit dot,
757 // this will cause it.m_pos to represent the end iterator
758 it
.m_pos
+= it
.m_element
.m_pathname
.size();
760 // if the end is reached, we are done
761 if (it
.m_pos
== it
.m_path_ptr
->m_pathname
.size())
763 it
.m_element
.clear(); // aids debugging, may release unneeded memory
767 // both POSIX and Windows treat paths that begin with exactly two separators specially
768 bool was_net(it
.m_element
.m_pathname
.size() > 2
769 && detail::is_directory_separator(it
.m_element
.m_pathname
[0])
770 && detail::is_directory_separator(it
.m_element
.m_pathname
[1])
771 && !detail::is_directory_separator(it
.m_element
.m_pathname
[2]));
773 // process separator (Windows drive spec is only case not a separator)
774 if (detail::is_directory_separator(it
.m_path_ptr
->m_pathname
[it
.m_pos
]))
776 // detect root directory
778 # ifdef BOOST_WINDOWS_API
780 || it
.m_element
.m_pathname
[it
.m_element
.m_pathname
.size()-1] == colon
784 it
.m_element
.m_pathname
= separator
; // generic format; see docs
788 // skip separators until it.m_pos points to the start of the next element
789 while (it
.m_pos
!= it
.m_path_ptr
->m_pathname
.size()
790 && detail::is_directory_separator(it
.m_path_ptr
->m_pathname
[it
.m_pos
]))
793 // detect trailing separator, and treat it as ".", per POSIX spec
794 if (it
.m_pos
== it
.m_path_ptr
->m_pathname
.size()
795 && !is_root_separator(it
.m_path_ptr
->m_pathname
, it
.m_pos
-1))
798 it
.m_element
= detail::dot_path();
804 size_type
end_pos(it
.m_path_ptr
->m_pathname
.find_first_of(separators
, it
.m_pos
));
805 if (end_pos
== string_type::npos
)
806 end_pos
= it
.m_path_ptr
->m_pathname
.size();
807 it
.m_element
= it
.m_path_ptr
->m_pathname
.substr(it
.m_pos
, end_pos
- it
.m_pos
);
810 BOOST_FILESYSTEM_DECL
void path::m_path_iterator_decrement(path::iterator
& it
)
812 BOOST_ASSERT_MSG(it
.m_pos
, "path::iterator decrement past begin()");
814 size_type
end_pos(it
.m_pos
);
816 // if at end and there was a trailing non-root '/', return "."
817 if (it
.m_pos
== it
.m_path_ptr
->m_pathname
.size()
818 && it
.m_path_ptr
->m_pathname
.size() > 1
819 && detail::is_directory_separator(it
.m_path_ptr
->m_pathname
[it
.m_pos
-1])
820 && !is_root_separator(it
.m_path_ptr
->m_pathname
, it
.m_pos
-1)
824 it
.m_element
= detail::dot_path();
828 size_type
root_dir_pos(root_directory_start(it
.m_path_ptr
->m_pathname
, end_pos
));
830 // skip separators unless root directory
834 && (end_pos
-1) != root_dir_pos
835 && detail::is_directory_separator(it
.m_path_ptr
->m_pathname
[end_pos
-1])
839 it
.m_pos
= filename_pos(it
.m_path_ptr
->m_pathname
, end_pos
);
840 it
.m_element
= it
.m_path_ptr
->m_pathname
.substr(it
.m_pos
, end_pos
- it
.m_pos
);
841 if (it
.m_element
.m_pathname
== preferred_separator_string
) // needed for Windows, harmless on POSIX
842 it
.m_element
.m_pathname
= separator_string
; // generic format; see docs
845 } // namespace filesystem
851 //------------------------------------------------------------------------------------//
853 //------------------------------------------------------------------------------------//
855 // Prior versions of these locale and codecvt implementations tried to take advantage
856 // of static initialization where possible, kept a local copy of the current codecvt
857 // facet (to avoid codecvt() having to call use_facet()), and was not multi-threading
858 // safe (again for efficiency).
860 // This was error prone, and required different implementation techniques depending
861 // on the compiler and also whether static or dynamic linking was used. Furthermore,
862 // users could not easily provide their multi-threading safe wrappers because the
863 // path interface requires the implementation itself to call codecvt() to obtain the
864 // default facet, and the initialization of the static within path_locale() could race.
866 // The code below is portable to all platforms, is much simpler, and hopefully will be
867 // much more robust. Timing tests (on Windows, using a Visual C++ release build)
868 // indicated the current code is roughly 9% slower than the previous code, and that
869 // seems a small price to pay for better code that is easier to use.
871 std::locale
default_locale()
873 # if defined(BOOST_WINDOWS_API)
874 std::locale global_loc
= std::locale();
875 return std::locale(global_loc
, new windows_file_codecvt
);
876 # elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \
877 || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
878 // "All BSD system functions expect their string parameters to be in UTF-8 encoding
879 // and nothing else." See
880 // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html
882 // "The kernel will reject any filename that is not a valid UTF-8 string, and it will
883 // even be normalized (to Unicode NFD) before stored on disk, at least when using HFS.
884 // The right way to deal with it would be to always convert the filename to UTF-8
885 // before trying to open/create a file." See
886 // http://lists.apple.com/archives/unix-porting/2007/Sep/msg00023.html
888 // "How a file name looks at the API level depends on the API. Current Carbon APIs
889 // handle file names as an array of UTF-16 characters; POSIX ones handle them as an
890 // array of UTF-8, which is why UTF-8 works well in Terminal. How it's stored on disk
891 // depends on the disk format; HFS+ uses UTF-16, but that's not important in most
893 // http://lists.apple.com/archives/applescript-users/2002/Sep/msg00319.html
895 // Many thanks to Peter Dimov for digging out the above references!
897 std::locale global_loc
= std::locale();
898 return std::locale(global_loc
, new boost::filesystem::detail::utf8_codecvt_facet
);
899 # else // Other POSIX
900 // ISO C calls std::locale("") "the locale-specific native environment", and this
901 // locale is the default for many POSIX-based operating systems such as Linux.
902 return std::locale("");
906 std::locale
& path_locale()
907 // std::locale("") construction, needed on non-Apple POSIX systems, can throw
908 // (if environmental variables LC_MESSAGES or LANG are wrong, for example), so
909 // path_locale() provides lazy initialization via a local static to ensure that any
910 // exceptions occur after main() starts and so can be caught. Furthermore,
911 // path_locale() is only called if path::codecvt() or path::imbue() are themselves
912 // actually called, ensuring that an exception will only be thrown if std::locale("")
915 // [locale] paragraph 6: Once a facet reference is obtained from a locale object by
916 // calling use_facet<>, that reference remains usable, and the results from member
917 // functions of it may be cached and re-used, as long as some locale object refers
919 static std::locale
loc(default_locale());
920 #ifdef BOOST_FILESYSTEM_DEBUG
921 std::cout
<< "***** path_locale() called" << std::endl
;
925 } // unnamed namespace
927 //--------------------------------------------------------------------------------------//
928 // path::codecvt() and path::imbue() implementation //
929 //--------------------------------------------------------------------------------------//
935 // See comments above
937 BOOST_FILESYSTEM_DECL
const path::codecvt_type
& path::codecvt()
939 #ifdef BOOST_FILESYSTEM_DEBUG
940 std::cout
<< "***** path::codecvt() called" << std::endl
;
942 BOOST_ASSERT_MSG(&path_locale(), "boost::filesystem::path locale initialization error");
944 return std::use_facet
<std::codecvt
<wchar_t, char, std::mbstate_t> >(path_locale());
947 BOOST_FILESYSTEM_DECL
std::locale
path::imbue(const std::locale
& loc
)
949 #ifdef BOOST_FILESYSTEM_DEBUG
950 std::cout
<< "***** path::imbue() called" << std::endl
;
952 std::locale
temp(path_locale());
957 } // namespace filesystem