Index: boost/filesystem/v3/operations.hpp =================================================================== --- boost/filesystem/v3/operations.hpp (revision 65864) +++ boost/filesystem/v3/operations.hpp (working copy) @@ -188,6 +188,8 @@ BOOST_FILESYSTEM_DECL path system_complete(const path& p, system::error_code* ec=0); BOOST_FILESYSTEM_DECL + path temp_dir_path(system::error_code* ec=0); + BOOST_FILESYSTEM_DECL path unique_path(const path& p, system::error_code* ec=0); } // namespace detail @@ -443,6 +445,12 @@ path system_complete(const path& p, system::error_code& ec) {return detail::system_complete(p, &ec);} inline + path temp_dir_path() {return detail::temp_dir_path();} + + inline + path temp_dir_path(system::error_code& ec) + {return detail::temp_dir_path(&ec);} + inline path unique_path(const path& p="%%%%-%%%%-%%%%-%%%%") { return detail::unique_path(p); } inline @@ -982,6 +990,7 @@ using filesystem3::symlink_file; using filesystem3::symlink_status; using filesystem3::system_complete; + using filesystem3::temp_dir_path; using filesystem3::type_unknown; using filesystem3::unique_path; # ifndef BOOST_FILESYSTEM_NO_DEPRECATED Index: libs/filesystem/v3/test/operations_test.cpp =================================================================== --- libs/filesystem/v3/test/operations_test.cpp (revision 65864) +++ libs/filesystem/v3/test/operations_test.cpp (working copy) @@ -45,6 +45,29 @@ #ifdef BOOST_WINDOWS_API # include + +inline std::wstring convert(const char* c) +{ + std::string s(c); + + return std::wstring(s.begin(), s.end()); +} + +inline int setenv(const char* name, const fs::path::value_type* val, int) +{ + return SetEnvironmentVariableW(convert(name).c_str(), val); +} + +inline int setenv(const char* name, const char* val, int) +{ + return SetEnvironmentVariableW(convert(name).c_str(), convert(val).c_str()); +} + +inline int unsetenv(const char* name) +{ + return SetEnvironmentVariableW(convert(name).c_str(), 0); +} + #endif // on Windows, except for standard libaries known to have wchar_t overloads for @@ -1269,6 +1292,191 @@ BOOST_TEST(!fs::equivalent(ng, file_ph)); } + // temp_dir_path_tests ---------------------------------------------------------// + + struct guarded_env_var + { + struct previous_value + { + std::string m_name; + std::string m_string; + bool m_empty; + + previous_value(const char* name) + : m_string(name) + , m_empty (true) + { + if(const char* value = getenv(name)) + { + m_string.assign(value); + m_empty = false; + } + else + { + m_empty = true; + } + } + ~previous_value() + { + m_empty? unsetenv(m_name.c_str()) + : setenv(m_name.c_str(), m_string.c_str(), 1); + } + }; + + previous_value m_previous_value; + + guarded_env_var(const char* name, const fs::path::value_type* value) + : m_previous_value(name) + { + value? setenv(name, value, 1) : unsetenv(name); + } + }; + + void temp_dir_path_tests() + { + { + std::cout << "temp_dir_path_tests..." << std::endl; + + BOOST_TEST(!fs::temp_dir_path().empty()); + BOOST_TEST(exists(fs::temp_dir_path())); + fs::path ph = fs::temp_dir_path()/"temp_dir_path_test.txt"; + { + if(exists(ph)) remove(ph); + std::ofstream f(ph.BOOST_FILESYSTEM_C_STR); + f << "passed"; + } + BOOST_TEST(exists(ph)); + { + std::ifstream f(ph.BOOST_FILESYSTEM_C_STR); + std::string s; + f >> s; + BOOST_TEST(s == "passed"); + } + remove(ph); + BOOST_TEST(!exists(ph)); + } + + fs::path test_temp_dir = init_path; + +#if defined BOOST_POSIX_API + { + struct guarded_tmp_vars + { + guarded_env_var m_tmpdir ; + guarded_env_var m_tmp ; + guarded_env_var m_temp ; + guarded_env_var m_tempdir; + + guarded_tmp_vars + ( const fs::path::value_type* tmpdir + , const fs::path::value_type* tmp + , const fs::path::value_type* temp + , const fs::path::value_type* tempdir + ) + : m_tmpdir ("TMPDIR" , tmpdir ) + , m_tmp ("TMP" , tmp ) + , m_temp ("TEMP" , temp ) + , m_tempdir("TEMPDIR", tempdir) + {} + }; + + try + { + guarded_tmp_vars vars(0, 0, 0, 0); + fs::path ph = fs::temp_dir_path(); + + BOOST_TEST(false); // should throw + } + catch(const boost::filesystem::filesystem_error& e) + { + BOOST_TEST(e.code() == boost::system::errc::not_a_directory); + } + + { + guarded_tmp_vars vars(0, 0, 0, 0); + error_code ec; + fs::path ph = fs::temp_dir_path(ec); + BOOST_TEST(ec); + BOOST_TEST(ec == boost::system::errc::not_a_directory); + } + + { + guarded_tmp_vars vars(test_temp_dir.BOOST_FILESYSTEM_C_STR, 0, 0, 0); + fs::path ph = fs::temp_dir_path(); + BOOST_TEST(equivalent(test_temp_dir, ph)); + } + { + guarded_tmp_vars vars(0, test_temp_dir.BOOST_FILESYSTEM_C_STR, 0, 0); + fs::path ph = fs::temp_dir_path(); + BOOST_TEST(equivalent(test_temp_dir, ph)); + } + { + guarded_tmp_vars vars(0, 0, test_temp_dir.BOOST_FILESYSTEM_C_STR, 0); + fs::path ph = fs::temp_dir_path(); + BOOST_TEST(equivalent(test_temp_dir, ph)); + } + { + guarded_tmp_vars vars(0, 0, 0, test_temp_dir.BOOST_FILESYSTEM_C_STR); + fs::path ph = fs::temp_dir_path(); + BOOST_TEST(equivalent(test_temp_dir, ph)); + } + } +#endif + +#if defined BOOST_WINDOWS_API + { + struct guarded_tmp_vars + { + guarded_env_var m_tmp ; + guarded_env_var m_temp ; + guarded_env_var m_userprofile; + + guarded_tmp_vars + ( const fs::path::value_type* tmp + , const fs::path::value_type* temp + , const fs::path::value_type* userprofile + ) + : m_tmp ("TMP" , tmp ) + , m_temp ("TEMP" , temp ) + , m_userprofile("USERPROFILE", userprofile) + {} + }; + + // should NEVER throw - the windows directory or current_path always exists + { + guarded_tmp_vars vars(0, 0, 0); + fs::path ph = fs::temp_dir_path(); + + BOOST_TEST(test_temp_dir != ph); + } + + // should NEVER fail - the windows directory or current_path always exists + { + guarded_tmp_vars vars(0, 0, 0); + error_code ec; + fs::path ph = fs::temp_dir_path(ec); + BOOST_TEST(!ec); + } + + { + guarded_tmp_vars vars(test_temp_dir.BOOST_FILESYSTEM_C_STR, 0, 0); + fs::path ph = fs::temp_dir_path(); + BOOST_TEST(equivalent(test_temp_dir, ph)); + } + { + guarded_tmp_vars vars(0, test_temp_dir.BOOST_FILESYSTEM_C_STR, 0); + fs::path ph = fs::temp_dir_path(); + BOOST_TEST(equivalent(test_temp_dir, ph)); + } + { + guarded_tmp_vars vars(0, 0, test_temp_dir.BOOST_FILESYSTEM_C_STR); + fs::path ph = fs::temp_dir_path(); + BOOST_TEST(equivalent(test_temp_dir, ph)); + } + } +#endif + } + // _tests --------------------------------------------------------------------------// void _tests() @@ -1393,7 +1601,9 @@ if (create_symlink_ok) // only if symlinks supported remove_symlink_tests(); write_time_tests(dir); - + + temp_dir_path_tests(); + std::cout << "testing complete" << std::endl; // post-test cleanup Index: libs/filesystem/v3/doc/reference.html =================================================================== --- libs/filesystem/v3/doc/reference.html (revision 65864) +++ libs/filesystem/v3/doc/reference.html (working copy) @@ -114,6 +114,7 @@      status_known
     symlink_status
     system_complete
+     temp_dir_path
     unique_path File streams
@@ -437,6 +438,9 @@ path system_complete(const path& p); path system_complete(const path& p, system::error_code& ec); + path temp_dir_path(); + path temp_dir_path(system::error_code& ec); + path unique_path(const path& model="%%%%-%%%%-%%%%-%%%%"); path unique_path(const path& model, system::error_code& ec); @@ -2442,6 +2446,19 @@

See complete() note for usage suggestions. -- end note]

+
path temp_dir_path();
+path temp_dir_path(system::error_code& ec);
+
+

Returns: The temporary directory path as returned by the POSIX getenv("TMPDIR") environment variable, + or the Windows GetTempPath API function. is_directory() is true for the returned path. +

+

Throws: As specified in + Error reporting.

+

[Note: The temp_dir_path() name was chosen to emphasize that the return is a + path, not just a single directory name.

+

For POSIX systems the definition of the first existing environment variable from the list: TMPDIR, TMP, TEMP, TEMPDIR is used. +   -- end note]

+
path unique_path(const path& model="%%%%-%%%%-%%%%-%%%%");
 path unique_path(const path& model, system::error_code& ec);
Index: libs/filesystem/v3/src/operations.cpp =================================================================== --- libs/filesystem/v3/src/operations.cpp (revision 65864) +++ libs/filesystem/v3/src/operations.cpp (working copy) @@ -49,6 +49,7 @@ #include #include #include // for malloc, free +#include #ifdef BOOST_FILEYSTEM_INCLUDE_IOSTREAM # include @@ -1445,6 +1446,54 @@ } BOOST_FILESYSTEM_DECL + path temp_dir_path(system::error_code* ec) + { +# ifdef BOOST_POSIX_API + const char* val = 0; + + (val = std::getenv("TMPDIR" )) || + (val = std::getenv("TMP" )) || + (val = std::getenv("TEMP" )) || + (val = std::getenv("TEMPDIR")); + + path p((val!=0)? val : ""); + + if(!val||(ec&&!is_directory(p, *ec))||(!ec&&!is_directory(p))) + { + errno = ENOTDIR; + error(true, ec, "boost::filesystem::temp_dir_path"); + return p; + } + + return p; + +# else // Windows + + std::vector buf(GetTempPathW(0, NULL)); + + if(buf.empty() || GetTempPathW(buf.size(), &buf[0])==0) + { + if(!buf.empty()) ::SetLastError(ENOTDIR); + error(true, ec, "boost::filesystem::temp_dir_path"); + return path(); + } + + buf.pop_back(); + + path p(buf.begin(), buf.end()); + + if((ec&&!is_directory(p, *ec))||(!ec&&!is_directory(p))) + { + ::SetLastError(ENOTDIR); + error(true, ec, "boost::filesystem::temp_dir_path"); + return path(); + } + + return p; +# endif + } + + BOOST_FILESYSTEM_DECL path system_complete(const path& p, system::error_code* ec) { # ifdef BOOST_POSIX_API