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 // Old standard library configurations, particularly MingGW, don't support wide strings.
11 // Report this with an explicit error message.
12 #include <boost/config.hpp>
13 # if defined( BOOST_NO_STD_WSTRING )
14 # error Configuration not supported: Boost.Filesystem V3 and later requires std::wstring support
17 // define BOOST_FILESYSTEM_SOURCE so that <boost/system/config.hpp> knows
18 // the library is being built (possibly exporting rather than importing code)
19 #define BOOST_FILESYSTEM_SOURCE
21 #ifndef BOOST_SYSTEM_NO_DEPRECATED
22 # define BOOST_SYSTEM_NO_DEPRECATED
25 #include <boost/filesystem/config.hpp>
26 #include <boost/filesystem/path.hpp>
27 #include <boost/filesystem/operations.hpp> // for filesystem_error
28 #include <boost/scoped_array.hpp>
29 #include <boost/system/error_code.hpp>
30 #include <boost/assert.hpp>
36 #ifdef BOOST_WINDOWS_API
37 # include "windows_file_codecvt.hpp"
39 #elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \
40 || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
41 # include <boost/filesystem/detail/utf8_codecvt_facet.hpp>
44 #ifdef BOOST_FILESYSTEM_DEBUG
49 namespace fs
= boost::filesystem
;
51 using boost::filesystem::path
;
56 using boost::system::error_code
;
58 //--------------------------------------------------------------------------------------//
60 // class path helpers //
62 //--------------------------------------------------------------------------------------//
66 //------------------------------------------------------------------------------------//
67 // miscellaneous class path helpers //
68 //------------------------------------------------------------------------------------//
70 typedef path::value_type value_type
;
71 typedef path::string_type string_type
;
72 typedef string_type::size_type size_type
;
74 # ifdef BOOST_WINDOWS_API
76 const wchar_t separator
= L
'/';
77 const wchar_t* const separators
= L
"/\\";
78 const wchar_t* separator_string
= L
"/";
79 const wchar_t* preferred_separator_string
= L
"\\";
80 const wchar_t colon
= L
':';
81 const wchar_t dot
= L
'.';
82 const wchar_t questionmark
= L
'?';
84 inline bool is_letter(wchar_t c
)
86 return (c
>= L
'a' && c
<=L
'z') || (c
>= L
'A' && c
<=L
'Z');
91 const char separator
= '/';
92 const char* const separators
= "/";
93 const char* separator_string
= "/";
94 const char* preferred_separator_string
= "/";
99 inline bool is_separator(fs::path::value_type c
)
101 return c
== separator
102 # ifdef BOOST_WINDOWS_API
103 || c
== path::preferred_separator
108 bool is_root_separator(const string_type
& str
, size_type pos
);
109 // pos is position of the separator
111 size_type
filename_pos(const string_type
& str
,
112 size_type end_pos
); // end_pos is past-the-end position
113 // Returns: 0 if str itself is filename (or empty)
115 size_type
root_directory_start(const string_type
& path
, size_type size
);
116 // Returns: npos if no root_directory found
119 const string_type
& src
,
120 size_type
& element_pos
,
121 size_type
& element_size
,
122 # if !BOOST_WORKAROUND(BOOST_MSVC, <= 1310) // VC++ 7.1
123 size_type size
= string_type::npos
129 } // unnamed namespace
131 //--------------------------------------------------------------------------------------//
133 // class path implementation //
135 //--------------------------------------------------------------------------------------//
141 path
& path::operator/=(const path
& p
)
145 if (this == &p
) // self-append
148 if (!is_separator(rhs
.m_pathname
[0]))
149 m_append_separator_if_needed();
150 m_pathname
+= rhs
.m_pathname
;
154 if (!is_separator(*p
.m_pathname
.begin()))
155 m_append_separator_if_needed();
156 m_pathname
+= p
.m_pathname
;
161 path
& path::operator/=(const value_type
* ptr
)
165 if (ptr
>= m_pathname
.data()
166 && ptr
< m_pathname
.data() + m_pathname
.size()) // overlapping source
169 if (!is_separator(rhs
.m_pathname
[0]))
170 m_append_separator_if_needed();
171 m_pathname
+= rhs
.m_pathname
;
175 if (!is_separator(*ptr
))
176 m_append_separator_if_needed();
182 int path::compare(const path
& p
) const BOOST_NOEXCEPT
184 return detail::lex_compare(begin(), end(), p
.begin(), p
.end());
187 # ifdef BOOST_WINDOWS_API
189 const std::string
path::generic_string() const
192 std::replace(tmp
.m_pathname
.begin(), tmp
.m_pathname
.end(), L
'\\', L
'/');
196 const std::string
path::generic_string(const codecvt_type
& cvt
) const
199 std::replace(tmp
.m_pathname
.begin(), tmp
.m_pathname
.end(), L
'\\', L
'/');
200 return tmp
.string(cvt
);
203 const std::wstring
path::generic_wstring() const
206 std::replace(tmp
.m_pathname
.begin(), tmp
.m_pathname
.end(), L
'\\', L
'/');
207 return tmp
.wstring();
210 # endif // BOOST_WINDOWS_API
212 // m_append_separator_if_needed ----------------------------------------------------//
214 path::string_type::size_type
path::m_append_separator_if_needed()
216 if (!m_pathname
.empty() &&
217 # ifdef BOOST_WINDOWS_API
218 *(m_pathname
.end()-1) != colon
&&
220 !is_separator(*(m_pathname
.end()-1)))
222 string_type::size_type
tmp(m_pathname
.size());
223 m_pathname
+= preferred_separator
;
229 // m_erase_redundant_separator -----------------------------------------------------//
231 void path::m_erase_redundant_separator(string_type::size_type sep_pos
)
233 if (sep_pos
// a separator was added
234 && sep_pos
< m_pathname
.size() // and something was appended
235 && (m_pathname
[sep_pos
+1] == separator
// and it was also separator
236 # ifdef BOOST_WINDOWS_API
237 || m_pathname
[sep_pos
+1] == preferred_separator
// or preferred_separator
239 )) { m_pathname
.erase(sep_pos
, 1); } // erase the added separator
242 // modifiers -----------------------------------------------------------------------//
244 # ifdef BOOST_WINDOWS_API
245 path
& path::make_preferred()
247 std::replace(m_pathname
.begin(), m_pathname
.end(), L
'/', L
'\\');
252 path
& path::remove_filename()
254 m_pathname
.erase(m_parent_path_end());
258 path
& path::remove_trailing_separator()
260 if (!m_pathname
.empty() && is_separator(m_pathname
[m_pathname
.size() - 1]))
261 m_pathname
.erase(m_pathname
.size() - 1);
265 path
& path::replace_extension(const path
& new_extension
)
267 // erase existing extension, including the dot, if any
268 m_pathname
.erase(m_pathname
.size()-extension().m_pathname
.size());
270 if (!new_extension
.empty())
272 // append new_extension, adding the dot if necessary
273 if (new_extension
.m_pathname
[0] != dot
)
274 m_pathname
.push_back(dot
);
275 m_pathname
.append(new_extension
.m_pathname
);
281 // decomposition -------------------------------------------------------------------//
283 path
path::root_path() const
285 path
temp(root_name());
286 if (!root_directory().empty()) temp
.m_pathname
+= root_directory().c_str();
290 path
path::root_name() const
292 iterator
itr(begin());
294 return (itr
.m_pos
!= m_pathname
.size()
296 (itr
.m_element
.m_pathname
.size() > 1
297 && is_separator(itr
.m_element
.m_pathname
[0])
298 && is_separator(itr
.m_element
.m_pathname
[1])
300 # ifdef BOOST_WINDOWS_API
301 || itr
.m_element
.m_pathname
[itr
.m_element
.m_pathname
.size()-1] == colon
308 path
path::root_directory() const
310 size_type
pos(root_directory_start(m_pathname
, m_pathname
.size()));
312 return pos
== string_type::npos
314 : path(m_pathname
.c_str() + pos
, m_pathname
.c_str() + pos
+ 1);
317 path
path::relative_path() const
319 iterator
itr(begin());
321 for (; itr
.m_pos
!= m_pathname
.size()
322 && (is_separator(itr
.m_element
.m_pathname
[0])
323 # ifdef BOOST_WINDOWS_API
324 || itr
.m_element
.m_pathname
[itr
.m_element
.m_pathname
.size()-1] == colon
328 return path(m_pathname
.c_str() + itr
.m_pos
);
331 string_type::size_type
path::m_parent_path_end() const
333 size_type
end_pos(filename_pos(m_pathname
, m_pathname
.size()));
335 bool filename_was_separator(m_pathname
.size()
336 && is_separator(m_pathname
[end_pos
]));
338 // skip separators unless root directory
339 size_type
root_dir_pos(root_directory_start(m_pathname
, end_pos
));
342 && (end_pos
-1) != root_dir_pos
343 && is_separator(m_pathname
[end_pos
-1])
347 return (end_pos
== 1 && root_dir_pos
== 0 && filename_was_separator
)
352 path
path::parent_path() const
354 size_type
end_pos(m_parent_path_end());
355 return end_pos
== string_type::npos
357 : path(m_pathname
.c_str(), m_pathname
.c_str() + end_pos
);
360 path
path::filename() const
362 size_type
pos(filename_pos(m_pathname
, m_pathname
.size()));
363 return (m_pathname
.size()
365 && is_separator(m_pathname
[pos
])
366 && !is_root_separator(m_pathname
, pos
))
368 : path(m_pathname
.c_str() + pos
);
371 path
path::stem() const
373 path
name(filename());
374 if (name
== detail::dot_path() || name
== detail::dot_dot_path()) return name
;
375 size_type
pos(name
.m_pathname
.rfind(dot
));
376 return pos
== string_type::npos
378 : path(name
.m_pathname
.c_str(), name
.m_pathname
.c_str() + pos
);
381 path
path::extension() const
383 path
name(filename());
384 if (name
== detail::dot_path() || name
== detail::dot_dot_path()) return path();
385 size_type
pos(name
.m_pathname
.rfind(dot
));
386 return pos
== string_type::npos
388 : path(name
.m_pathname
.c_str() + pos
);
391 // lexical operations --------------------------------------------------------------//
395 // C++14 provide a mismatch algorithm with four iterator arguments(), but earlier
396 // standard libraries didn't, so provide this needed functionality.
398 std::pair
<path::iterator
, path::iterator
> mismatch(path::iterator it1
,
399 path::iterator it1end
, path::iterator it2
, path::iterator it2end
)
401 for (; it1
!= it1end
&& it2
!= it2end
&& *it1
== *it2
;)
406 return std::make_pair(it1
, it2
);
410 path
path::lexically_relative(const path
& base
) const
412 std::pair
<path::iterator
, path::iterator
> mm
413 = detail::mismatch(begin(), end(), base
.begin(), base
.end());
414 if (mm
.first
== begin() && mm
.second
== base
.begin())
416 if (mm
.first
== end() && mm
.second
== base
.end())
417 return detail::dot_path();
419 for (; mm
.second
!= base
.end(); ++mm
.second
)
420 tmp
/= detail::dot_dot_path();
421 for (; mm
.first
!= end(); ++mm
.first
)
426 // normal --------------------------------------------------------------------------//
428 path
path::lexically_normal() const
430 if (m_pathname
.empty())
434 iterator
start(begin());
435 iterator
last(end());
436 iterator
stop(last
--);
437 for (iterator
itr(start
); itr
!= stop
; ++itr
)
439 // ignore "." except at start and last
440 if (itr
->native().size() == 1
441 && (itr
->native())[0] == dot
443 && itr
!= last
) continue;
445 // ignore a name and following ".."
447 && itr
->native().size() == 2
448 && (itr
->native())[0] == dot
449 && (itr
->native())[1] == dot
) // dot dot
451 string_type
lf(temp
.filename().native());
455 && lf
[0] != separator
))
459 # ifdef BOOST_WINDOWS_API
466 temp
.remove_filename();
467 //// if not root directory, must also remove "/" if any
468 //if (temp.native().size() > 0
469 // && temp.native()[temp.native().size()-1]
472 // string_type::size_type rds(
473 // root_directory_start(temp.native(), temp.native().size()));
474 // if (rds == string_type::npos
475 // || rds != temp.native().size()-1)
477 // temp.m_pathname.erase(temp.native().size()-1);
482 if (temp
.empty() && ++next
!= stop
483 && next
== last
&& *last
== detail::dot_path())
485 temp
/= detail::dot_path();
495 temp
/= detail::dot_path();
499 } // namespace filesystem
502 //--------------------------------------------------------------------------------------//
504 // class path helpers implementation //
506 //--------------------------------------------------------------------------------------//
511 // is_root_separator ---------------------------------------------------------------//
513 bool is_root_separator(const string_type
& str
, size_type pos
)
514 // pos is position of the separator
516 BOOST_ASSERT_MSG(!str
.empty() && is_separator(str
[pos
]),
517 "precondition violation");
519 // subsequent logic expects pos to be for leftmost slash of a set
520 while (pos
> 0 && is_separator(str
[pos
-1]))
527 # ifdef BOOST_WINDOWS_API
529 if (pos
== 2 && is_letter(str
[0]) && str
[1] == colon
)
534 if (pos
< 3 || !is_separator(str
[0]) || !is_separator(str
[1]))
537 return str
.find_first_of(separators
, 2) == pos
;
540 // filename_pos --------------------------------------------------------------------//
542 size_type
filename_pos(const string_type
& str
,
543 size_type end_pos
) // end_pos is past-the-end position
544 // return 0 if str itself is filename (or empty)
548 && is_separator(str
[0])
549 && is_separator(str
[1])) return 0;
552 if (end_pos
&& is_separator(str
[end_pos
-1]))
555 // set pos to start of last element
556 size_type
pos(str
.find_last_of(separators
, end_pos
-1));
558 # ifdef BOOST_WINDOWS_API
559 if (pos
== string_type::npos
&& end_pos
> 1)
560 pos
= str
.find_last_of(colon
, end_pos
-2);
563 return (pos
== string_type::npos
// path itself must be a filename (or empty)
564 || (pos
== 1 && is_separator(str
[0]))) // or net
565 ? 0 // so filename is entire string
566 : pos
+ 1; // or starts after delimiter
569 // root_directory_start ------------------------------------------------------------//
571 size_type
root_directory_start(const string_type
& path
, size_type size
)
572 // return npos if no root_directory found
575 # ifdef BOOST_WINDOWS_API
579 && is_separator(path
[2])) return 2;
584 && is_separator(path
[0])
585 && is_separator(path
[1])) return string_type::npos
;
587 # ifdef BOOST_WINDOWS_API
590 && is_separator(path
[0])
591 && is_separator(path
[1])
592 && path
[2] == questionmark
593 && is_separator(path
[3]))
595 string_type::size_type
pos(path
.find_first_of(separators
, 4));
596 return pos
< size
? pos
: string_type::npos
;
602 && is_separator(path
[0])
603 && is_separator(path
[1])
604 && !is_separator(path
[2]))
606 string_type::size_type
pos(path
.find_first_of(separators
, 2));
607 return pos
< size
? pos
: string_type::npos
;
611 if (size
> 0 && is_separator(path
[0])) return 0;
613 return string_type::npos
;
616 // first_element --------------------------------------------------------------------//
617 // sets pos and len of first element, excluding extra separators
618 // if src.empty(), sets pos,len, to 0,0.
621 const string_type
& src
,
622 size_type
& element_pos
,
623 size_type
& element_size
,
627 if (size
== string_type::npos
) size
= src
.size();
630 if (src
.empty()) return;
632 string_type::size_type
cur(0);
634 // deal with // [network]
635 if (size
>= 2 && is_separator(src
[0])
636 && is_separator(src
[1])
638 || !is_separator(src
[2])))
644 // leading (not non-network) separator
645 else if (is_separator(src
[0]))
648 // bypass extra leading separators
650 && is_separator(src
[cur
+1]))
658 // at this point, we have either a plain name, a network name,
659 // or (on Windows only) a device name
663 # ifdef BOOST_WINDOWS_API
666 && !is_separator(src
[cur
]))
672 # ifdef BOOST_WINDOWS_API
673 if (cur
== size
) return;
674 // include device delimiter
675 if (src
[cur
] == colon
)
682 } // unnamed namespace
691 BOOST_FILESYSTEM_DECL
692 int lex_compare(path::iterator first1
, path::iterator last1
,
693 path::iterator first2
, path::iterator last2
)
695 for (; first1
!= last1
&& first2
!= last2
;)
697 if (first1
->native() < first2
->native()) return -1;
698 if (first2
->native() < first1
->native()) return 1;
699 BOOST_ASSERT(first2
->native() == first1
->native());
703 if (first1
== last1
&& first2
== last2
)
705 return first1
== last1
? -1 : 1;
708 BOOST_FILESYSTEM_DECL
709 const path
& dot_path()
711 # ifdef BOOST_WINDOWS_API
712 static const fs::path
dot_pth(L
".");
714 static const fs::path
dot_pth(".");
719 BOOST_FILESYSTEM_DECL
720 const path
& dot_dot_path()
722 # ifdef BOOST_WINDOWS_API
723 static const fs::path
dot_dot(L
"..");
725 static const fs::path
dot_dot("..");
731 //--------------------------------------------------------------------------------------//
733 // class path::iterator implementation //
735 //--------------------------------------------------------------------------------------//
737 path::iterator
path::begin() const
740 itr
.m_path_ptr
= this;
741 size_type element_size
;
742 first_element(m_pathname
, itr
.m_pos
, element_size
);
743 itr
.m_element
= m_pathname
.substr(itr
.m_pos
, element_size
);
744 if (itr
.m_element
.m_pathname
== preferred_separator_string
)
745 itr
.m_element
.m_pathname
= separator_string
; // needed for Windows, harmless on POSIX
749 path::iterator
path::end() const
752 itr
.m_path_ptr
= this;
753 itr
.m_pos
= m_pathname
.size();
757 void path::m_path_iterator_increment(path::iterator
& it
)
759 BOOST_ASSERT_MSG(it
.m_pos
< it
.m_path_ptr
->m_pathname
.size(),
760 "path::basic_iterator increment past end()");
762 // increment to position past current element; if current element is implicit dot,
763 // this will cause it.m_pos to represent the end iterator
764 it
.m_pos
+= it
.m_element
.m_pathname
.size();
766 // if the end is reached, we are done
767 if (it
.m_pos
== it
.m_path_ptr
->m_pathname
.size())
769 it
.m_element
.clear(); // aids debugging, may release unneeded memory
773 // both POSIX and Windows treat paths that begin with exactly two separators specially
774 bool was_net(it
.m_element
.m_pathname
.size() > 2
775 && is_separator(it
.m_element
.m_pathname
[0])
776 && is_separator(it
.m_element
.m_pathname
[1])
777 && !is_separator(it
.m_element
.m_pathname
[2]));
779 // process separator (Windows drive spec is only case not a separator)
780 if (is_separator(it
.m_path_ptr
->m_pathname
[it
.m_pos
]))
782 // detect root directory
784 # ifdef BOOST_WINDOWS_API
786 || it
.m_element
.m_pathname
[it
.m_element
.m_pathname
.size()-1] == colon
790 it
.m_element
.m_pathname
= separator
; // generic format; see docs
794 // skip separators until it.m_pos points to the start of the next element
795 while (it
.m_pos
!= it
.m_path_ptr
->m_pathname
.size()
796 && is_separator(it
.m_path_ptr
->m_pathname
[it
.m_pos
]))
799 // detect trailing separator, and treat it as ".", per POSIX spec
800 if (it
.m_pos
== it
.m_path_ptr
->m_pathname
.size()
801 && !is_root_separator(it
.m_path_ptr
->m_pathname
, it
.m_pos
-1))
804 it
.m_element
= detail::dot_path();
810 size_type
end_pos(it
.m_path_ptr
->m_pathname
.find_first_of(separators
, it
.m_pos
));
811 if (end_pos
== string_type::npos
)
812 end_pos
= it
.m_path_ptr
->m_pathname
.size();
813 it
.m_element
= it
.m_path_ptr
->m_pathname
.substr(it
.m_pos
, end_pos
- it
.m_pos
);
816 void path::m_path_iterator_decrement(path::iterator
& it
)
818 BOOST_ASSERT_MSG(it
.m_pos
, "path::iterator decrement past begin()");
820 size_type
end_pos(it
.m_pos
);
822 // if at end and there was a trailing non-root '/', return "."
823 if (it
.m_pos
== it
.m_path_ptr
->m_pathname
.size()
824 && it
.m_path_ptr
->m_pathname
.size() > 1
825 && is_separator(it
.m_path_ptr
->m_pathname
[it
.m_pos
-1])
826 && !is_root_separator(it
.m_path_ptr
->m_pathname
, it
.m_pos
-1)
830 it
.m_element
= detail::dot_path();
834 size_type
root_dir_pos(root_directory_start(it
.m_path_ptr
->m_pathname
, end_pos
));
836 // skip separators unless root directory
840 && (end_pos
-1) != root_dir_pos
841 && is_separator(it
.m_path_ptr
->m_pathname
[end_pos
-1])
845 it
.m_pos
= filename_pos(it
.m_path_ptr
->m_pathname
, end_pos
);
846 it
.m_element
= it
.m_path_ptr
->m_pathname
.substr(it
.m_pos
, end_pos
- it
.m_pos
);
847 if (it
.m_element
.m_pathname
== preferred_separator_string
) // needed for Windows, harmless on POSIX
848 it
.m_element
.m_pathname
= separator_string
; // generic format; see docs
851 } // namespace filesystem
857 //------------------------------------------------------------------------------------//
859 //------------------------------------------------------------------------------------//
861 // Prior versions of these locale and codecvt implementations tried to take advantage
862 // of static initialization where possible, kept a local copy of the current codecvt
863 // facet (to avoid codecvt() having to call use_facet()), and was not multi-threading
864 // safe (again for efficiency).
866 // This was error prone, and required different implementation techniques depending
867 // on the compiler and also whether static or dynamic linking was used. Furthermore,
868 // users could not easily provide their multi-threading safe wrappers because the
869 // path interface requires the implementation itself to call codecvt() to obtain the
870 // default facet, and the initialization of the static within path_locale() could race.
872 // The code below is portable to all platforms, is much simpler, and hopefully will be
873 // much more robust. Timing tests (on Windows, using a Visual C++ release build)
874 // indicated the current code is roughly 9% slower than the previous code, and that
875 // seems a small price to pay for better code that is easier to use.
877 std::locale
default_locale()
879 # if defined(BOOST_WINDOWS_API)
880 std::locale global_loc
= std::locale();
881 return std::locale(global_loc
, new windows_file_codecvt
);
882 # elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \
883 || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
884 // "All BSD system functions expect their string parameters to be in UTF-8 encoding
885 // and nothing else." See
886 // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html
888 // "The kernel will reject any filename that is not a valid UTF-8 string, and it will
889 // even be normalized (to Unicode NFD) before stored on disk, at least when using HFS.
890 // The right way to deal with it would be to always convert the filename to UTF-8
891 // before trying to open/create a file." See
892 // http://lists.apple.com/archives/unix-porting/2007/Sep/msg00023.html
894 // "How a file name looks at the API level depends on the API. Current Carbon APIs
895 // handle file names as an array of UTF-16 characters; POSIX ones handle them as an
896 // array of UTF-8, which is why UTF-8 works well in Terminal. How it's stored on disk
897 // depends on the disk format; HFS+ uses UTF-16, but that's not important in most
899 // http://lists.apple.com/archives/applescript-users/2002/Sep/msg00319.html
901 // Many thanks to Peter Dimov for digging out the above references!
903 std::locale global_loc
= std::locale();
904 return std::locale(global_loc
, new boost::filesystem::detail::utf8_codecvt_facet
);
905 # else // Other POSIX
906 // ISO C calls std::locale("") "the locale-specific native environment", and this
907 // locale is the default for many POSIX-based operating systems such as Linux.
908 return std::locale("");
912 std::locale
& path_locale()
913 // std::locale("") construction, needed on non-Apple POSIX systems, can throw
914 // (if environmental variables LC_MESSAGES or LANG are wrong, for example), so
915 // path_locale() provides lazy initialization via a local static to ensure that any
916 // exceptions occur after main() starts and so can be caught. Furthermore,
917 // path_locale() is only called if path::codecvt() or path::imbue() are themselves
918 // actually called, ensuring that an exception will only be thrown if std::locale("")
921 // [locale] paragraph 6: Once a facet reference is obtained from a locale object by
922 // calling use_facet<>, that reference remains usable, and the results from member
923 // functions of it may be cached and re-used, as long as some locale object refers
925 static std::locale
loc(default_locale());
926 #ifdef BOOST_FILESYSTEM_DEBUG
927 std::cout
<< "***** path_locale() called" << std::endl
;
931 } // unnamed namespace
933 //--------------------------------------------------------------------------------------//
934 // path::codecvt() and path::imbue() implementation //
935 //--------------------------------------------------------------------------------------//
941 // See comments above
943 const path::codecvt_type
& path::codecvt()
945 #ifdef BOOST_FILESYSTEM_DEBUG
946 std::cout
<< "***** path::codecvt() called" << std::endl
;
948 BOOST_ASSERT_MSG(&path_locale(), "boost::filesystem::path locale initialization error");
950 return std::use_facet
<std::codecvt
<wchar_t, char, std::mbstate_t> >(path_locale());
953 std::locale
path::imbue(const std::locale
& loc
)
955 #ifdef BOOST_FILESYSTEM_DEBUG
956 std::cout
<< "***** path::imbue() called" << std::endl
;
958 std::locale
temp(path_locale());
963 } // namespace filesystem