diff --git a/doc/relative_proposal.html b/doc/relative_proposal.html index c56328a..544e563 100644 --- a/doc/relative_proposal.html +++ b/doc/relative_proposal.html @@ -45,32 +45,45 @@

New class path member functions

-

The class path normal_relative and -relative member functions perform lexical processing only, and so do not -follow symlinks. For existing path, or partially existing paths, that may -contain symlinks use the relative operational functions which do +

The  normal and +relative member functions, like all member functions of class path, perform lexical processing +only. They do not follow symlinks.

-
path  normal_relative(const path& base) const;
+

These semantics are useful for operating on paths that do not currently exist +or on paths generated by operational non-member functions that resolve symlinks.

+
path normal() const;
- Returns: normal(*this).relative(normal(base)).
+

Returns: A path with the same elements  as *this +except that redundant current (dot) directory and name element followed +by parent (dot-dot) directory elements are removed. If the returned path +would otherwise be empty, a path containing a single current (dot) +directory is returned.

+

Remarks: Uses operator/= to compose the returned path.

+

[Example:

+

assert(path("foo/./bar/..").normal() == path("foo");
+assert(path("foo/./bar/../").normal() == path("foo/.");

+

All of the above asserts would succeed. On Windows, the +returned path's separators would be backslashes rather than slashes, but that +does not affect equality. —end example]

+ -
path  relative(const path& base) const;
+
path relative(const path& base) const;

Returns:

-

Remarks: Uses std::mismatch(begin(), end(), +

Remarks: Uses std::mismatch(begin(), end(), base.begin(), base.end()) to determine the first mismatched element. - Path equality is determined by operator==.

+ Path equality is determined by operator==. Uses operator/= + to compose the returned path.

+ +

[Note: Use the non-member operational function relative + if symlink following semantics are desired. —end note]

+ +

[Note: Use the normal function to preprocess . —end note]

+ +

[Example:

+

assert(path("/a/d").relative("/a/b/c") == path("../../d"));
+assert(path("/a/b/c").relative("/a/d") == path("../b/c"));
+assert(path("a/b/c").relative("a") == path("b/c"));
+assert(path("a/b/c").relative("a/b/c/x/y") == path("../.."));
+assert(path("a/b/c").relative("a/b/c") == path("."));

+

All of the above asserts would succeed. On Windows, the +returned path's separators would be backslashes rather than slashes, but that +does not affect equality. —end example]

New operational functions

path weakly_canonical(const path& p);
-path weakly_canonical(const path& p, system::error_code& ec)
-
 
+path weakly_canonical(const path& p, system::error_code& ec); +
+Returns:
    +
  • +

    If exists(p), canonical(p)

  • +
  • +

    Otherwise, p.parent_path().empty()
    + ? p
    + : weakly_canonical(p.parent_path()) / p.filename()
    .

  • +
+

Remarks: An implementation may use iteration +rather than recursion.

+

Throws:  As specified in Error reporting.

+
path relative(const path& p, system::error_code& ec);

Returns: relative(p, current_path(), ec).

Throws:  As specified in Error reporting.

-
path relative(const path& p, const path& base=current_path());
+
path relative(const path& p, const path& base=current_path());
+path relative(const path& p, const path& base, system::error_code& ec);
-

Returns: weakly_canonical(p).relative(weakly_canonical(base)).

-

Throws: As specified in Error reporting.

-
-
path relative(const path& p, const path& base, system::error_code& ec);
-
-
-

Effects: Creates a temporary object path wc_base -with a value of weakly_canonical(base, ec) and, if no -error occurred, creates another temporary object path wc_p -with a value of weakly_canonical(p, ec).

-

Returns: wc_p.relative(wc_base) if no error -occurred during processing of Effects, otherwise path().

-

Remarks: Names wc_base and wc_p -are for exposition only. These names are not exposed to callers of -relative.

+

Returns: weakly_canonical(p[, ec]).relative(weakly_canonical(base[, +ec])). The second form returns +path() if an error occurs.

Throws: As specified in Error reporting.

+

[Note: For two paths a and b that both exist, + relative(a, b) is equivalent + to canonical(a).relative(canonical(b)).

+

For two paths a and b neither of which exist, + relative(a, b) is equivalent + to a.relative(b). —end note]


@@ -122,7 +159,7 @@ relative
.

Distributed under the Boost Software License, Version 1.0. See www.boost.org/LICENSE_1_0.txt

Revised -11 August 2015

+12 August 2015

diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index 8a49747..02fe3d3 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -24,3 +24,4 @@ exe tut5 : tut5.cpp ; exe path_info : path_info.cpp ; exe file_status : file_status.cpp ; exe file_size : file_size.cpp ; +exe directory_symlink_parent_resolution : directory_symlink_parent_resolution.cpp ; \ No newline at end of file diff --git a/example/directory_symlink_parent_resolution.cpp b/example/directory_symlink_parent_resolution.cpp new file mode 100644 index 0000000..a204b6e --- /dev/null +++ b/example/directory_symlink_parent_resolution.cpp @@ -0,0 +1,41 @@ +// directory_symlink_parent_resolution.cpp -------------------------------------------// + +// Copyright Beman Dawes 2015 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#include +#include +#include +#include +#include +using std::cout; +using std::endl; +using namespace boost::filesystem; + +int cpp_main(int argc, char* argv[]) +{ +# ifdef BOOST_WINDOWS_API + cout << "BOOST_WINDOWS_API" << endl; +# else + cout << "BOOST_POSIX_API" << endl; +# endif + + path test_dir(current_path() / "dspr_demo"); + + remove_all(test_dir); + create_directories(test_dir / "a/c/d"); + current_path(test_dir / "a"); + create_directory_symlink("c/d", "b"); + save_string_file("name.txt", "Windows"); + save_string_file("c/name.txt", "POSIX"); + current_path(test_dir); + std::string s; + load_string_file("a/b/../name.txt", s); + cout << s << endl; + + return 0; +} diff --git a/example/msvc/directory_symlink_parent_resolution/directory_symlink_parent_resolution.vcxproj b/example/msvc/directory_symlink_parent_resolution/directory_symlink_parent_resolution.vcxproj new file mode 100644 index 0000000..243e4d6 --- /dev/null +++ b/example/msvc/directory_symlink_parent_resolution/directory_symlink_parent_resolution.vcxproj @@ -0,0 +1,170 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + {489B5052-4C97-4551-B8C5-1C0C3BD040E8} + Win32Proj + directory_symlink_parent_resolution + 8.1 + + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + Application + true + v140 + Unicode + + + Application + false + v140 + true + Unicode + + + + + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + "$(TargetDir)\$(TargetName).exe" + + + + + + + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + + + "$(TargetDir)\$(TargetName).exe" + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + "$(TargetDir)\$(TargetName).exe" + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + + + "$(TargetDir)\$(TargetName).exe" + + + + + + \ No newline at end of file diff --git a/example/msvc/filesystem-tutorials.sln b/example/msvc/filesystem-tutorials.sln index 91b9844..e41ee55 100644 --- a/example/msvc/filesystem-tutorials.sln +++ b/example/msvc/filesystem-tutorials.sln @@ -15,6 +15,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tut5", "tut5\tut5.vcxproj", EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "path_info", "path_info\path_info.vcxproj", "{A37B7F28-3261-41BF-8BC1-8384BD4C8E47}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "directory_symlink_parent_resolution", "directory_symlink_parent_resolution\directory_symlink_parent_resolution.vcxproj", "{489B5052-4C97-4551-B8C5-1C0C3BD040E8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -71,6 +73,14 @@ Global {A37B7F28-3261-41BF-8BC1-8384BD4C8E47}.Release|x64.Build.0 = Release|x64 {A37B7F28-3261-41BF-8BC1-8384BD4C8E47}.Release|x86.ActiveCfg = Release|Win32 {A37B7F28-3261-41BF-8BC1-8384BD4C8E47}.Release|x86.Build.0 = Release|Win32 + {489B5052-4C97-4551-B8C5-1C0C3BD040E8}.Debug|x64.ActiveCfg = Debug|x64 + {489B5052-4C97-4551-B8C5-1C0C3BD040E8}.Debug|x64.Build.0 = Debug|x64 + {489B5052-4C97-4551-B8C5-1C0C3BD040E8}.Debug|x86.ActiveCfg = Debug|Win32 + {489B5052-4C97-4551-B8C5-1C0C3BD040E8}.Debug|x86.Build.0 = Debug|Win32 + {489B5052-4C97-4551-B8C5-1C0C3BD040E8}.Release|x64.ActiveCfg = Release|x64 + {489B5052-4C97-4551-B8C5-1C0C3BD040E8}.Release|x64.Build.0 = Release|x64 + {489B5052-4C97-4551-B8C5-1C0C3BD040E8}.Release|x86.ActiveCfg = Release|Win32 + {489B5052-4C97-4551-B8C5-1C0C3BD040E8}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/include/boost/filesystem/path.hpp b/include/boost/filesystem/path.hpp index 3255e5b..0ead184 100644 --- a/include/boost/filesystem/path.hpp +++ b/include/boost/filesystem/path.hpp @@ -519,7 +519,7 @@ namespace filesystem // ----- lexical operations ----- path normal() const; - path relative(const path& p) const; + path relative(const path& base) const; // TODO: document dangers of lack of symlink following, no normalization, // difference of "symlink/.." handling between Windows and POSIX diff --git a/include/boost/filesystem/string_file.hpp b/include/boost/filesystem/string_file.hpp new file mode 100644 index 0000000..f8310ee --- /dev/null +++ b/include/boost/filesystem/string_file.hpp @@ -0,0 +1,43 @@ +// filesystem/string_file.hpp --------------------------------------------------------// + +// Copyright Beman Dawes 2015 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// Library home page: http://www.boost.org/libs/filesystem + +#ifndef BOOST_FILESYSTEM_FILE_SAVER_HPP +#define BOOST_FILESYSTEM_FILE_SAVER_HPP + +#include +#include +#include + +namespace boost +{ +namespace filesystem +{ +inline +void save_string_file(const path& p, const std::string& contents) +{ + std::ofstream file; + file.exceptions(std::ofstream::failbit | std::ofstream::badbit); + file.open(p.string(), std::ios_base::binary); + file.write(contents.c_str(), contents.size()); +} + +inline +void load_string_file(const path& p, std::string& str) +{ + std::ifstream file; + file.exceptions(std::ifstream::failbit | std::ifstream::badbit); + file.open(p.string(), std::ios_base::binary); + std::size_t sz = static_cast(boost::filesystem::file_size(p)); + str.resize(sz, '\0'); + file.read(&str[0], sz); +} +} // namespace filesystem +} // namespace boost + +#endif // include guard diff --git a/src/operations.cpp b/src/operations.cpp index fff0b36..12e026b 100644 --- a/src/operations.cpp +++ b/src/operations.cpp @@ -1522,10 +1522,10 @@ namespace detail path relative(const path& p, const path& base, error_code* ec) { error_code tmp_ec; - path wc_base = weakly_canonical(base, &tmp_ec); + path wc_base(weakly_canonical(base, &tmp_ec)); if (error(tmp_ec.value(), base, ec, "boost::filesystem::relative")) return path(); - path wc_p = weakly_canonical(p, &tmp_ec); + path wc_p(weakly_canonical(p, &tmp_ec)); if (error(tmp_ec.value(), base, ec, "boost::filesystem::relative")) return path(); return wc_p.relative(wc_base); diff --git a/test/path_test.cpp b/test/path_test.cpp index 3b203a1..cdba55b 100644 --- a/test/path_test.cpp +++ b/test/path_test.cpp @@ -1837,7 +1837,11 @@ namespace PATH_TEST_EQ(path("foo/../bar").normal().generic(), "bar"); PATH_TEST_EQ(path("foo/../bar/").normal().generic(), "bar/."); PATH_TEST_EQ(path("foo/bar/..").normal().generic(), "foo"); + PATH_TEST_EQ(path("foo/./bar/..").normal().generic(), "foo"); + std::cout << path("foo/./bar/..").normal() << std::endl; // outputs "foo" PATH_TEST_EQ(path("foo/bar/../").normal().generic(), "foo/."); + PATH_TEST_EQ(path("foo/./bar/../").normal().generic(), "foo/."); + std::cout << path("foo/./bar/../").normal() << std::endl; // POSIX: "foo/.", Windows: "foo\." PATH_TEST_EQ(path("foo/bar/../..").normal().generic(), "."); PATH_TEST_EQ(path("foo/bar/../../").normal().generic(), "./."); PATH_TEST_EQ(path("foo/bar/../blah").normal().generic(), "foo/blah");