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