Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r74851 - in branches/release: boost boost/filesystem boost/filesystem/v3 libs/filesystem libs/filesystem/v3/doc libs/filesystem/v3/src libs/filesystem/v3/test libs/filesystem/v3/test/msvc10
From: bdawes_at_[hidden]
Date: 2011-10-09 09:54:10


Author: bemandawes
Date: 2011-10-09 09:54:09 EDT (Sun, 09 Oct 2011)
New Revision: 74851
URL: http://svn.boost.org/trac/boost/changeset/74851

Log:
Merge trunk, including hash and canonical support
Added:
   branches/release/libs/filesystem/v3/test/locale_info.cpp
      - copied unchanged from r74850, /trunk/libs/filesystem/v3/test/locale_info.cpp
Properties modified:
   branches/release/boost/filesystem/ (props changed)
   branches/release/boost/filesystem.hpp (props changed)
   branches/release/libs/filesystem/ (props changed)
Text files modified:
   branches/release/boost/filesystem/v3/operations.hpp | 15 ++++
   branches/release/boost/filesystem/v3/path.hpp | 18 ++++
   branches/release/libs/filesystem/v3/doc/reference.html | 122 ++++++++++++++++++++++++++--------
   branches/release/libs/filesystem/v3/doc/release_history.html | 22 ++++++
   branches/release/libs/filesystem/v3/src/operations.cpp | 84 ++++++++++++++++++++++++
   branches/release/libs/filesystem/v3/test/msvc10/filesystem-v3.sln | 2
   branches/release/libs/filesystem/v3/test/operations_test.cpp | 138 ++++++++++++++++++++++++++++-----------
   branches/release/libs/filesystem/v3/test/path_unit_test.cpp | 7 ++
   8 files changed, 333 insertions(+), 75 deletions(-)

Modified: branches/release/boost/filesystem/v3/operations.hpp
==============================================================================
--- branches/release/boost/filesystem/v3/operations.hpp (original)
+++ branches/release/boost/filesystem/v3/operations.hpp 2011-10-09 09:54:09 EDT (Sun, 09 Oct 2011)
@@ -142,6 +142,8 @@
     BOOST_FILESYSTEM_DECL
     path initial_path(system::error_code* ec=0);
     BOOST_FILESYSTEM_DECL
+ path canonical(const path& p, const path& base, system::error_code* ec=0);
+ BOOST_FILESYSTEM_DECL
     void copy(const path& from, const path& to, system::error_code* ec=0);
     BOOST_FILESYSTEM_DECL
     void copy_directory(const path& from, const path& to, system::error_code* ec=0);
@@ -268,7 +270,17 @@
   path absolute(const path& p, const path& base=current_path());
   // If base.is_absolute(), throws nothing. Thus no need for ec argument
 
-# ifndef BOOST_FILESYSTEM_NO_DEPRECATED
+ inline
+ path canonical(const path& p, const path& base=current_path())
+ {return detail::canonical(p, base);}
+ inline
+ path canonical(const path& p, system::error_code& ec)
+ {return detail::canonical(p, current_path(), &ec);}
+ inline
+ path canonical(const path& p, const path& base, system::error_code& ec)
+ {return detail::canonical(p, base, &ec);}
+
+ # ifndef BOOST_FILESYSTEM_NO_DEPRECATED
   inline
   path complete(const path& p)
   {
@@ -990,6 +1002,7 @@
   {
     using filesystem3::absolute;
     using filesystem3::block_file;
+ using filesystem3::canonical;
     using filesystem3::character_file;
 // using filesystem3::copy;
     using filesystem3::copy_file;

Modified: branches/release/boost/filesystem/v3/path.hpp
==============================================================================
--- branches/release/boost/filesystem/v3/path.hpp (original)
+++ branches/release/boost/filesystem/v3/path.hpp 2011-10-09 09:54:09 EDT (Sun, 09 Oct 2011)
@@ -29,6 +29,7 @@
 #include <boost/shared_ptr.hpp>
 #include <boost/io/detail/quoted_manip.hpp>
 #include <boost/static_assert.hpp>
+#include <boost/functional/hash_fwd.hpp>
 #include <string>
 #include <iterator>
 #include <cstring>
@@ -559,18 +560,31 @@
     const path::value_type* l(lhs.c_str());
     while ((*l == *rhs || (*l == L'\\' && *rhs == L'/') || (*l == L'/' && *rhs == L'\\'))
       && *l) { ++l; ++rhs; }
- return *l == *rhs || (*l == L'\\' && *rhs == L'/') || (*l == L'/' && *rhs == L'\\');
+ return *l == *rhs;
   }
   inline bool operator==(const path& lhs, const path& rhs) { return lhs == rhs.c_str(); }
   inline bool operator==(const path& lhs, const path::string_type& rhs) { return lhs == rhs.c_str(); }
   inline bool operator==(const path::string_type& lhs, const path& rhs) { return rhs == lhs.c_str(); }
   inline bool operator==(const path::value_type* lhs, const path& rhs) { return rhs == lhs; }
+
+ inline std::size_t hash_value(const path& x)
+ {
+ std::size_t seed = 0;
+ for(const path::value_type* it = x.c_str(); *it; ++it)
+ hash_combine(seed, *it == '/' ? L'\\' : *it);
+ return seed;
+ }
 # else // BOOST_POSIX_API
   inline bool operator==(const path& lhs, const path& rhs) { return lhs.native() == rhs.native(); }
   inline bool operator==(const path& lhs, const path::string_type& rhs) { return lhs.native() == rhs; }
   inline bool operator==(const path& lhs, const path::value_type* rhs) { return lhs.native() == rhs; }
   inline bool operator==(const path::string_type& lhs, const path& rhs) { return lhs == rhs.native(); }
   inline bool operator==(const path::value_type* lhs, const path& rhs) { return lhs == rhs.native(); }
+
+ inline std::size_t hash_value(const path& x)
+ {
+ return hash_range(x.native().begin(), x.native().end());
+ }
 # endif
 
   inline bool operator!=(const path& lhs, const path& rhs) { return !(lhs == rhs); }
@@ -592,7 +606,7 @@
   operator<<(std::basic_ostream<Char, Traits>& os, const path& p)
   {
     return os
- << boost::io::quoted(p.string<std::basic_string<Char> >(), static_cast<Char>('&'));
+ << boost::io::quoted(p.template string<std::basic_string<Char> >(), static_cast<Char>('&'));
   }
   
   template <class Char, class Traits>

Modified: branches/release/libs/filesystem/v3/doc/reference.html
==============================================================================
--- branches/release/libs/filesystem/v3/doc/reference.html (original)
+++ branches/release/libs/filesystem/v3/doc/reference.html 2011-10-09 09:54:09 EDT (Sun, 09 Oct 2011)
@@ -8,6 +8,15 @@
 <title>Filesystem V3 Reference
 </title>
 <link rel="stylesheet" type="text/css" href="../../../../doc/src/minimal.css">
+<style type="text/css">
+ pre {background-color:#D7EEFF}
+ body
+ {
+ font-family: sans-serif;
+ max-width : 8.5in;
+ margin: 1em;
+ }
+</style>
 </head>
 
 <body>
@@ -50,7 +59,7 @@
     <a href="#Definitions">Definitions</a><br>
     <a href="#Conformance">Conformance</a><br>
     <a href="#Header-filesystem-synopsis">
- Header &lt;filesystem&gt; synopsis</a><br>
+ Header &lt;boost/filesystem.hpp&gt; synopsis</a><br>
     <a href="#Error-reporting">Error reporting</a><br>
     <a href="#class-path">Class path</a><br>
     &nbsp;&nbsp;&nbsp; path constructors<br>
@@ -89,6 +98,7 @@
     <a href="#Operational-functions">
     Operational functions</a><br>
 &nbsp;&nbsp;&nbsp;&nbsp absolute<br>
+&nbsp;&nbsp;&nbsp;&nbsp; canonical<br>
 &nbsp;&nbsp;&nbsp;&nbsp; copy<br>
 &nbsp;&nbsp;&nbsp;&nbsp; copy_directory<br>
 &nbsp;&nbsp;&nbsp;&nbsp; copy_file<br>
@@ -158,11 +168,13 @@
   \</code>,<code> /</code>, and<code> |</code>&nbsp;<i>--end note]</i></p>
 </blockquote>
 <p><b><i><a name="Path">Path</a>:</i></b> A sequence of elements that identify
-a location within a filesystem. The elements are the <i>root-name<sub>opt</sub></i>, <i>
+the location of a file within a filesystem. The elements are the <i>root-name<sub>opt</sub></i>, <i>
 root-directory<sub>opt</sub></i>, and an optional sequence of filenames. [<i>Note:</i>
 A pathname is the concrete representation of a path. <i>--end note</i>]</p>
-<p><b><i><a name="Absolute-path">Absolute path</a>:</i></b> A path that uniquely
-identifies a file. The format is implementation defined. </p>
+<p><b><i><a name="Absolute-path">Absolute path</a>:</i></b> A path that
+unambiguously
+identifies the location of a file within a filesystem without reference to an
+additional starting location. The format is implementation defined. </p>
 <blockquote>
   <p><i>[Note:</i> For POSIX-like implementations, including<b> </b>Unix
   variants, Linux, and Mac OS X, only paths
@@ -173,9 +185,13 @@
   specifier followed by a slash, or begin with two slashes, are absolute paths.&nbsp;<i>--end
   note]</i></p>
 </blockquote>
-<p><b><a name="Relative-path">Relative path</a>:</b> A path that uniquely
-identifies a file only when considered relative to some other path. [<i>Note:</i>
+<p><b><a name="Relative-path">Relative path</a>:</b> A path that only
+unambiguously
+identifies the location of a file within a filesystem when resolved relative to
+a starting location. The format is implementation defined. [<i>Note:</i>
 Paths &quot;.&quot; and &quot;..&quot; are considered to be relative paths. <i>--end note</i>]</p>
+<p><b><a name="Canonical-path">Canonical path</a>:</b> An absolute path that has
+no elements which are symbolic links, and no dot or dot dot elements.</p>
 <p><i><b><a name="Pathname">Pathname</a>:</b> </i>A character string that represents a
 path. Pathnames are formatted according to the generic pathname format or the
 native pathname format.</p>
@@ -288,7 +304,7 @@
 is unreasonable for a program to detect them prior to calling the function. <i>
 -- end note</i>]</p>
 </blockquote>
-<h2><a name="Header-filesystem-synopsis">Header <code>&lt;boost/filesystem&gt;</code> synopsis</a></h2>
+<h2><a name="Header-filesystem-synopsis">Header <code>&lt;boost/filesystem.hpp&gt;</code> synopsis</a></h2>
 <pre> namespace boost
   {
     namespace filesystem
@@ -298,6 +314,7 @@
       void swap(path&amp; lhs, path&amp; rhs);
       bool lexicographical_compare(path::iterator first1, path::iterator last1,
                                    path::iterator first2, path::iterator last2);
+ std::size_t hash_value(const path&amp; p);
 
       bool operator==(const path&amp; lhs, const path&amp; rhs);
       bool operator!=(const path&amp; lhs, const path&amp; rhs);
@@ -354,6 +371,10 @@
 
       path absolute(const path&amp; p, const path&amp; base=current_path());
 
+ path canonical(const path&amp; p, const path&amp; base = current_path());
+ path canonical(const path&amp; p, system::error_code&amp; ec);
+ path canonical(const path&amp; p, const path&amp; base, system::error_code&amp; ec);
+
       void copy(const path&amp; from, const path&amp; to);
       void copy(const path&amp; from, const path&amp; to, system::error_code&amp; ec);
 
@@ -736,7 +757,7 @@
 
 <h3> <a name="path-constructors"> <code>
 <font size="4">path</font></code> constructors</a></h3>
-<pre>path();</pre>
+<pre><span style="background-color: #D7EEFF">path();</span></pre>
 <blockquote>
   <p><i>Postcondition:</i> <code>empty()</code>.</p>
   </blockquote>
@@ -987,7 +1008,7 @@
   <p><i>Returns:</i> <code>empty() ? path() : *--end()</code></p>
   <p>[<i>Example:</i></p>
   <blockquote>
- <pre><code>std::cout &lt;&lt; path(&quot;/foo/bar.txt&quot;).filename();</code> // outputs &quot;<code>bar.txt</code>&quot; (without the quotes)</pre>
+ <pre><code>std::cout &lt;&lt; path(&quot;/foo/bar.txt&quot;).filename();</code> // outputs &quot;<code>bar.txt</code>&quot;</pre>
   </blockquote>
   <p> <i>--end example</i>]</p>
 </blockquote>
@@ -1001,8 +1022,8 @@
   p.filename()</code>.</p>
   <p>[<i>Example:</i></p>
   <blockquote>
- <pre><code>std::cout &lt;&lt; path(&quot;/foo/bar.txt&quot;).stem();</code> // outputs &quot;<code>bar</code>&quot; (without the quotes)</pre>
- <pre>path p = &quot;foo.bar.baz.tar&quot;;
+ <pre><code>std::cout &lt;&lt; path(&quot;/foo/bar.txt&quot;).stem();</code> // outputs &quot;<code>bar</code>&quot;
+path p = &quot;foo.bar.baz.tar&quot;;
 for (; !p.extension().empty(); p = p.stem())
   std::cout &lt;&lt; p.extension() &lt;&lt; '\n';
   // outputs: .tar
@@ -1023,7 +1044,7 @@
   as alternate data streams or partitioned dataset names.</p>
   <p>[<i>Example:</i></p>
   <blockquote>
- <pre><code>std::cout &lt;&lt; path(&quot;/foo/bar.txt&quot;).extension(); //</code> outputs &quot;<code>.txt</code>&quot; (without the quotes)</pre>
+ <pre><code>std::cout &lt;&lt; path(&quot;/foo/bar.txt&quot;).extension(); //</code> outputs &quot;<code>.txt</code>&quot;</pre>
   </blockquote>
   <p> <i>--end example</i>]</p>
   <p>[<i>Note:<b> </b></i>The dot is included in the return value so that
@@ -1175,6 +1196,14 @@
   due to the <code>path</code> iterator's value type itself being <code>path</code>.
   <i>--end note</i>]</p>
 </blockquote>
+<pre>std::size_t <a name="hash_value">hash_value</a> (const path&amp; p);</pre>
+<blockquote>
+ <p><i>Returns:</i> A hash value for the path <code>p</code>. If
+ for two paths, <code>p1 == p2</code> then
+ <code>hash_value(p1) == hash_value(p2)</code>.</p>
+ <p>This allows paths to be used with
+ Boost.Hash.</p>
+</blockquote>
 <pre>bool operator&lt; (const path&amp; lhs, const path&amp; rhs);</pre>
 <blockquote>
   <p><i>Returns:</i> <code>return lexicographical_compare(lhs.begin(), lhs.end(),
@@ -1226,7 +1255,8 @@
 to ensure that paths with embedded spaces will round trip correctly. Ampersand (<code>&amp;</code>)
 is used as an escape character, so the path can itself contain double quotes.</p>
 <pre>template &lt;class Char, class Traits&gt;
-std::basic_ostream&lt;Char, Traits&gt;&amp; operator&lt;&lt;(std::basic_ostream&lt;Char, Traits&gt;&amp; os, const path&amp; p)
+std::basic_ostream&lt;Char, Traits&gt;&amp; operator&lt;&lt;(std::basic_ostream&lt;Char, Traits&gt;&amp; os,
+ const path&amp; p)
 </pre>
 <blockquote>
   <p><i>Effects:</i>&nbsp;
@@ -1236,7 +1266,8 @@
    <code>os</code></p>
 </blockquote>
 <pre>template &lt;class Char, class Traits&gt;
-inline std::basic_istream&lt;Char, Traits&gt;&amp; operator&gt;&gt;(std::basic_istream&lt;Char, Traits&gt;&amp; is, path&amp; p)
+inline std::basic_istream&lt;Char, Traits&gt;&amp; operator&gt;&gt;(std::basic_istream&lt;Char, Traits&gt;&amp; is,
+ path&amp; p)
 </pre>
 <blockquote>
   <p><i>Effects:&nbsp; </i>
@@ -1258,9 +1289,12 @@
       public:
         filesystem_error();
         filesystem_error(const filesystem_error&amp;);
- filesystem_error(const std::string&amp; what_arg, system::error_code ec);
- filesystem_error(const std::string&amp; what_arg, const path&amp; p1, system::error_code ec);
- filesystem_error(const std::string&amp; what_arg, const path&amp; p1, const path&amp; p2, system::error_code ec);
+ filesystem_error(const std::string&amp; what_arg,
+ system::error_code ec);
+ filesystem_error(const std::string&amp; what_arg,
+ const path&amp; p1, system::error_code ec);
+ filesystem_error(const std::string&amp; what_arg,
+ const path&amp; p1, const path&amp; p2, system::error_code ec);
 
         filesystem_error&amp; filesystem_error(const filesystem_error&amp;);
        ~filesystem_error();
@@ -1385,6 +1419,7 @@
   string.</p>
 </blockquote>
 <h3><a name="Class-directory_entry">Class <code>directory_entry</code></a></h3>
+<div dir="ltr">
 <pre> namespace boost
   {
     namespace filesystem
@@ -1396,13 +1431,16 @@
         // constructors and destructor
         directory_entry();
         directory_entry(const directory_entry&amp;);
- explicit directory_entry(const path_type&amp; p, file_status st=file_status(), file_status symlink_st=file_status());
+ explicit directory_entry(const path_type&amp; p, file_status st=file_status(),
+ file_status symlink_st=file_status());
        ~directory_entry();
 
         // modifiers
         directory_entry&amp; operator=(const directory_entry&amp;);
- void assign(const path_type&amp; p, file_status st=file_status(), file_status symlink_st=file_status());
- void replace_filename(const path&amp; p, file_status st=file_status(), file_status symlink_st=file_status());
+ void assign(const path_type&amp; p, file_status st=file_status(),
+ file_status symlink_st=file_status());
+ void replace_filename(const path&amp; p, file_status st=file_status(),
+ file_status symlink_st=file_status());
 
         // observers
         const path&amp; path() const;
@@ -1426,6 +1464,7 @@
 
     } // namespace filesystem
   } // namespace boost</pre>
+</div>
 <p>A <code>directory_entry</code> object stores a <code>path object</code>,
 a <code>file_status</code> object for non-symbolic link status, and a <code>
 file_status</code> object for symbolic link status. The <code>file_status</code>
@@ -1943,7 +1982,7 @@
 <h4><a name="Function-specifications">Operational function specifications</a></h4>
 <pre>path <a name="absolute">absolute</a>(const path&amp; p, const path&amp; base=current_path());</pre>
   <blockquote>
- <p><i>Returns:</i> A path composed according to to the
+ <p><i>Returns:</i> A absolute path composed according to the
   following table</p>
   <table border="1" cellpadding="5" cellspacing="0" bordercolor="#111111" style="border-collapse: collapse">
     <tr>
@@ -1965,11 +2004,31 @@
       <td align="center"><code>return absolute(base) / p</code></td>
     </tr>
   </table>
- <p><i>Postcondition:</i> For the returned path, <code>rp,</code> <code>
- rp.is_absolute()</code> is true.</p>
+ <p dir="ltr">[<i>Note:</i> For the returned path, <code>rp,</code> <code>
+ rp.is_absolute()</code> is true. <i>-- end note</i>]</p>
   <p><i>Throws:</i> If <code>base.is_absolute()</code> is true, throws only if
   memory allocation fails.</p>
 </blockquote>
+<pre>path <a name="canonical">canonical</a>(const path&amp; p, const path&amp; base = current_path());
+path canonical(const path&amp; p, system::error_code&amp; ec);
+path canonical(const path&amp; p, const path&amp; base, system::error_code&amp; ec);</pre>
+<blockquote>
+<p><i>Overview:</i> Converts <code>p</code>, which must exist, to an absolute
+path that has no symbolic link, dot,
+or dot-dot elements. </p>
+<p><i>Returns:</i> A canonical path that refers to
+the same file system object as <code>absolute(p,base)</code>. For the overload
+without a <code>base</code> argument, <code>base</code> is <code>current_path()</code>.</p>
+ <p><i>Throws:</i>&nbsp; As specified in
+ <a href="#Error-reporting">
+ Error reporting</a>.</p>
+
+ <p><i>Remarks:</i> <code>!exists(p)</code> is an error.</p>
+
+ <p>[<i>Note:</i> Canonical pathnames allow security checking of a path (eg.
+ does this path live in /home/goodguy or /home/badguy?)&nbsp; -- end note]</p>
+
+</blockquote>
 <pre>void <a name="copy">copy</a>(const path&amp; from, const path&amp; to);
 void copy(const path&amp; from, const path&amp; to, system::error_code&amp; ec);</pre>
 <blockquote>
@@ -3236,7 +3295,7 @@
 <p>The Windows API has many functions that also have Unicode versions to permit
 an extended-length path for a maximum total path length of 32,767 characters.
 ... To specify an extended-length path, use the <b>&quot;\\?\&quot; prefix</b>. For
-example, &quot;\\?\D:\very long path&quot;.&nbsp;
+example, &quot;\\?\D:\very long path&quot;.&nbsp;
 <i>[C++ string literals require backslashes be doubled, of course.]</i></p>
 </blockquote>
 <p>Because most Boost.Filesystem operational functions just pass the contents of
@@ -3271,12 +3330,14 @@
 Witt were particularly helpful in refining the library.</p>
 <p>The create_directories, extension, basename, and replace_extension functions
 were developed by Vladimir Prus. The temp_directory_path function was
-contributed by Jeff Flinn.</p>
+contributed by Jeff Flinn. David Svoboda suggested the canonical function and
+provided psuedo-code.</p>
 <p>Howard Hinnant and John Maddock reviewed a draft of the version 2 proposal, and
 identified a number of mistakes or weaknesses, resulting in a more polished
 final document.</p>
 <p>Peter Dimov suggested a single class path, with member templates to adapt to
 multiple string types. His idea became the basis for the version 3 path design.</p>
+<p>&nbsp;</p>
 <h2><a name="References">References</a></h2>
 <table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" width="100%">
   <tr>
@@ -3298,11 +3359,12 @@
   </tr>
 </table>
 <hr>
-<p>© Copyright Beman Dawes, 2002, 2006, 2007, 2009, 2010</p>
-<p>Distributed under the Boost Software License, Version 1.0. See
-www.boost.org/LICENSE_1_0.txt</p>
-<p>Revised
-<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B %Y" startspan -->12 April 2011<!--webbot bot="Timestamp" endspan i-checksum="28281" --></p>
+<p><font size="2">© Copyright Beman Dawes, 2002, 2006, 2007, 2009, 2010, 2011</font></p>
+<p><font size="2">Distributed under the Boost Software License, Version 1.0. See
+</font>
+www.boost.org/LICENSE_1_0.txt</p>
+<p><font size="2">Revised
+<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B %Y" startspan -->06 October 2011<!--webbot bot="Timestamp" endspan i-checksum="32189" --></font></p>
 
 </body>
 

Modified: branches/release/libs/filesystem/v3/doc/release_history.html
==============================================================================
--- branches/release/libs/filesystem/v3/doc/release_history.html (original)
+++ branches/release/libs/filesystem/v3/doc/release_history.html 2011-10-09 09:54:09 EDT (Sun, 09 Oct 2011)
@@ -36,6 +36,22 @@
   </tr>
 </table>
 
+<h2>1.48.0</h2>
+<ul>
+ <li>Added operational function canonical(),
+ suggested by David Svoboda, who also provided pseudo-code.</li>
+ <li>Added hash_value() function for
+ paths. (Daniel James)</li>
+ <li>Fix path inserter problem (#5764)
+ reported for QNX6.3.2 host (gcc-3.3.5)</li>
+ <li>Fix problem of locale(&quot;&quot;) exception being thrown before main() starts on
+ poorly configured (e.g. LANG=&quot;bad name&quot;) POSIX systems. Resolves the most
+ serious aspect of tickets
+ #4688,
+ #5100,
+ #5289.</li>
+</ul>
+
 <h2>1.47.0</h2>
 <ul>
   <li>Program file_status.cpp added (V3). See boost-root/libs/filesystem/v3/example.
@@ -46,6 +62,10 @@
 
 <h2>1.46.1</h2>
 
+<ul>
+ <li>Fix fstream problem for STLPort masquerading as Dinkumware (#5217).</li>
+</ul>
+
 <h2>1.46.0</h2>
 <ul>
   <li>Version 3 of the library is now the default.</li>
@@ -68,7 +88,7 @@
 </ul>
 <hr>
 <p>Revised
-<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->31 May, 2011<!--webbot bot="Timestamp" endspan i-checksum="13963" --></p>
+<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->03 October, 2011<!--webbot bot="Timestamp" endspan i-checksum="38359" --></p>
 <p>© Copyright Beman Dawes, 2011</p>
 <p> Use, modification, and distribution are subject to the Boost Software
 License, Version 1.0. See <a href="http://www.boost.org/LICENSE_1_0.txt">

Modified: branches/release/libs/filesystem/v3/src/operations.cpp
==============================================================================
--- branches/release/libs/filesystem/v3/src/operations.cpp (original)
+++ branches/release/libs/filesystem/v3/src/operations.cpp 2011-10-09 09:54:09 EDT (Sun, 09 Oct 2011)
@@ -77,6 +77,8 @@
 
 # ifdef BOOST_POSIX_API
 
+ const fs::path dot_path(".");
+ const fs::path dot_dot_path("..");
 # include <sys/types.h>
 # if !defined(__APPLE__) && !defined(__OpenBSD__)
 # include <sys/statvfs.h>
@@ -98,6 +100,8 @@
 
 # else // BOOST_WINDOW_API
 
+ const fs::path dot_path(L".");
+ const fs::path dot_dot_path(L"..");
 # if (defined(__MINGW32__) || defined(__CYGWIN__)) && !defined(WINVER)
       // Versions of MinGW or Cygwin that support Filesystem V3 support at least WINVER 0x501.
       // See MinGW's windef.h
@@ -752,6 +756,86 @@
   }
 
   BOOST_FILESYSTEM_DECL
+ path canonical(const path& p, const path& base, system::error_code* ec)
+ {
+ path source (p.is_absolute() ? p : absolute(p, base));
+ path result;
+
+ system::error_code local_ec;
+ file_status stat (status(source, local_ec));
+
+ if (stat.type() == fs::file_not_found)
+ {
+ if (ec == 0)
+ BOOST_FILESYSTEM_THROW(filesystem_error(
+ "boost::filesystem::canonical", source,
+ error_code(system::errc::no_such_file_or_directory, system::generic_category())));
+ ec->assign(system::errc::no_such_file_or_directory, system::generic_category());
+ return result;
+ }
+ else if (local_ec)
+ {
+ if (ec == 0)
+ BOOST_FILESYSTEM_THROW(filesystem_error(
+ "boost::filesystem::canonical", source, local_ec));
+ *ec = local_ec;
+ return result;
+ }
+
+ bool scan (true);
+ while (scan)
+ {
+ scan = false;
+ result.clear();
+ for (path::iterator itr = source.begin(); itr != source.end(); ++itr)
+ {
+ if (*itr == dot_path)
+ continue;
+ if (*itr == dot_dot_path)
+ {
+ result.remove_filename();
+ continue;
+ }
+
+ result /= *itr;
+
+ bool is_sym (is_symlink(detail::symlink_status(result, ec)));
+ if (ec && *ec)
+ return path();
+
+ if (is_sym)
+ {
+ path link(detail::read_symlink(result, ec));
+ if (ec && *ec)
+ return path();
+ result.remove_filename();
+
+ if (link.is_absolute())
+ {
+ for (++itr; itr != source.end(); ++itr)
+ link /= *itr;
+ source = link;
+ }
+ else // link is relative
+ {
+ path new_source(result);
+ new_source /= link;
+ for (++itr; itr != source.end(); ++itr)
+ new_source /= *itr;
+ source = new_source;
+ }
+ scan = true; // symlink causes scan to be restarted
+ break;
+ }
+ }
+ }
+ if (ec != 0)
+ ec->clear();
+ BOOST_ASSERT_MSG(result.is_absolute(), "canonical() implementation error; please report");
+ return result;
+ }
+
+ BOOST_FILESYSTEM_DECL
   void copy(const path& from, const path& to, system::error_code* ec)
   {
     file_status s(symlink_status(from, *ec));

Modified: branches/release/libs/filesystem/v3/test/msvc10/filesystem-v3.sln
==============================================================================
--- branches/release/libs/filesystem/v3/test/msvc10/filesystem-v3.sln (original)
+++ branches/release/libs/filesystem/v3/test/msvc10/filesystem-v3.sln 2011-10-09 09:54:09 EDT (Sun, 09 Oct 2011)
@@ -132,7 +132,9 @@
                 {256EA89A-E073-4CE8-B675-BE2FBC6B2691}.Release|Win32.ActiveCfg = Release|Win32
                 {256EA89A-E073-4CE8-B675-BE2FBC6B2691}.Release|Win32.Build.0 = Release|Win32
                 {FC5C770F-3017-4021-8DAF-C5DCA3FDF005}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FC5C770F-3017-4021-8DAF-C5DCA3FDF005}.Debug|Win32.Build.0 = Debug|Win32
                 {FC5C770F-3017-4021-8DAF-C5DCA3FDF005}.Release|Win32.ActiveCfg = Release|Win32
+ {FC5C770F-3017-4021-8DAF-C5DCA3FDF005}.Release|Win32.Build.0 = Release|Win32
                 {5C9B3380-3C6E-45CC-986A-16D245E27E58}.Debug|Win32.ActiveCfg = Debug|Win32
                 {5C9B3380-3C6E-45CC-986A-16D245E27E58}.Debug|Win32.Build.0 = Debug|Win32
                 {5C9B3380-3C6E-45CC-986A-16D245E27E58}.Release|Win32.ActiveCfg = Release|Win32

Modified: branches/release/libs/filesystem/v3/test/operations_test.cpp
==============================================================================
--- branches/release/libs/filesystem/v3/test/operations_test.cpp (original)
+++ branches/release/libs/filesystem/v3/test/operations_test.cpp 2011-10-09 09:54:09 EDT (Sun, 09 Oct 2011)
@@ -388,45 +388,46 @@
  
   void create_tree()
   {
+ cout << "creating test directories and files in " << dir << endl;
 
- // create directory d1
- BOOST_TEST(!fs::create_directory(dir));
- BOOST_TEST(!fs::is_symlink(dir));
- BOOST_TEST(!fs::is_symlink("nosuchfileordirectory"));
- d1 = dir / "d1";
- BOOST_TEST(fs::create_directory(d1));
- BOOST_TEST(fs::exists(d1));
- BOOST_TEST(fs::is_directory(d1));
- BOOST_TEST(fs::is_empty(d1));
-
- // create an empty file named "d1f1"
- d1f1 = d1 / "d1f1";
- create_file(d1f1, "");
- BOOST_TEST(fs::exists(d1f1));
- BOOST_TEST(!fs::is_directory(d1f1));
- BOOST_TEST(fs::is_regular_file(d1f1));
- BOOST_TEST(fs::is_empty(d1f1));
- BOOST_TEST(fs::file_size(d1f1) == 0);
- BOOST_TEST(fs::hard_link_count(d1f1) == 1);
-
- // create an empty file named "f0"
- f0 = dir / "f0";
- create_file(f0, "");
- BOOST_TEST(fs::exists(f0));
- BOOST_TEST(!fs::is_directory(f0));
- BOOST_TEST(fs::is_regular_file(f0));
- BOOST_TEST(fs::is_empty(f0));
- BOOST_TEST(fs::file_size(f0) == 0);
- BOOST_TEST(fs::hard_link_count(f0) == 1);
-
- // create a file named "f1"
- f1 = dir / "f1";
- create_file(f1, "file-f1");
- BOOST_TEST(fs::exists(f1));
- BOOST_TEST(!fs::is_directory(f1));
- BOOST_TEST(fs::is_regular_file(f1));
- BOOST_TEST(fs::file_size(f1) == 7);
- verify_file(f1, "file-f1");
+ // create directory d1
+ BOOST_TEST(!fs::create_directory(dir));
+ BOOST_TEST(!fs::is_symlink(dir));
+ BOOST_TEST(!fs::is_symlink("nosuchfileordirectory"));
+ d1 = dir / "d1";
+ BOOST_TEST(fs::create_directory(d1));
+ BOOST_TEST(fs::exists(d1));
+ BOOST_TEST(fs::is_directory(d1));
+ BOOST_TEST(fs::is_empty(d1));
+
+ // create an empty file named "d1f1"
+ d1f1 = d1 / "d1f1";
+ create_file(d1f1, "");
+ BOOST_TEST(fs::exists(d1f1));
+ BOOST_TEST(!fs::is_directory(d1f1));
+ BOOST_TEST(fs::is_regular_file(d1f1));
+ BOOST_TEST(fs::is_empty(d1f1));
+ BOOST_TEST(fs::file_size(d1f1) == 0);
+ BOOST_TEST(fs::hard_link_count(d1f1) == 1);
+
+ // create an empty file named "f0"
+ f0 = dir / "f0";
+ create_file(f0, "");
+ BOOST_TEST(fs::exists(f0));
+ BOOST_TEST(!fs::is_directory(f0));
+ BOOST_TEST(fs::is_regular_file(f0));
+ BOOST_TEST(fs::is_empty(f0));
+ BOOST_TEST(fs::file_size(f0) == 0);
+ BOOST_TEST(fs::hard_link_count(f0) == 1);
+
+ // create a file named "f1"
+ f1 = dir / "f1";
+ create_file(f1, "file-f1");
+ BOOST_TEST(fs::exists(f1));
+ BOOST_TEST(!fs::is_directory(f1));
+ BOOST_TEST(fs::is_regular_file(f1));
+ BOOST_TEST(fs::file_size(f1) == 7);
+ verify_file(f1, "file-f1");
   }
 
   // directory_iterator_tests --------------------------------------------------------//
@@ -1228,11 +1229,12 @@
     cout << "absolute_tests..." << endl;
 
     BOOST_TEST_EQ(fs::absolute(""), fs::current_path() );
+ BOOST_TEST_EQ(fs::absolute("", ""), fs::current_path() );
     BOOST_TEST_EQ(fs::absolute(fs::current_path() / "foo/bar"), fs::current_path() / "foo/bar");
     BOOST_TEST_EQ(fs::absolute("foo"), fs::current_path() / "foo");
     BOOST_TEST_EQ(fs::absolute("foo", fs::current_path()), fs::current_path() / "foo");
     BOOST_TEST_EQ(fs::absolute("bar", "foo"), fs::current_path() / "foo" / "bar");
- BOOST_TEST_EQ(fs::absolute("/foo"), fs::current_path().root_name().string() + "/foo");
+ BOOST_TEST_EQ(fs::absolute("/foo"), fs::current_path().root_path().string() + "foo");
 
 # ifdef BOOST_WINDOWS_API
     BOOST_TEST_EQ(fs::absolute("a:foo", "b:/bar"), "a:/bar/foo");
@@ -1295,7 +1297,58 @@
 
   }
 
- // copy_file_tests -----------------------------------------------------------------//
+ // canonical_basic_tests -----------------------------------------------------------//
+
+ void canonical_basic_tests()
+ {
+ cout << "canonical_basic_tests..." << endl;
+
+ // error handling
+ error_code ec;
+ ec.clear();
+ fs::canonical("no-such-file", ec);
+ BOOST_TEST(ec);
+ ec.clear();
+ fs::canonical("no-such-file", "x", ec);
+ BOOST_TEST(ec);
+ bool ok(false);
+ try { fs::canonical("no-such-file"); }
+ catch (const fs::filesystem_error&) { ok = true; }
+ BOOST_TEST(ok);
+
+ // non-symlink tests; also see canonical_symlink_tests()
+ BOOST_TEST_EQ(fs::canonical(""), fs::current_path());
+ BOOST_TEST_EQ(fs::canonical("", fs::current_path()), fs::current_path());
+ BOOST_TEST_EQ(fs::canonical("", ""), fs::current_path());
+ BOOST_TEST_EQ(fs::canonical(fs::current_path()), fs::current_path());
+ BOOST_TEST_EQ(fs::canonical(fs::current_path(), ""), fs::current_path());
+ BOOST_TEST_EQ(fs::canonical(fs::current_path(), "no-such-file"), fs::current_path());
+
+ BOOST_TEST_EQ(fs::canonical("."), fs::current_path());
+ BOOST_TEST_EQ(fs::canonical(".."), fs::current_path().parent_path());
+ BOOST_TEST_EQ(fs::canonical("/"), fs::current_path().root_path());
+
+ fs::path relative_dir(dir.filename());
+ BOOST_TEST_EQ(fs::canonical(dir), dir);
+ BOOST_TEST_EQ(fs::canonical(relative_dir), dir);
+ BOOST_TEST_EQ(fs::canonical(dir / "f0"), dir / "f0");
+ BOOST_TEST_EQ(fs::canonical(relative_dir / "f0"), dir / "f0");
+ BOOST_TEST_EQ(fs::canonical(relative_dir / "./f0"), dir / "f0");
+ BOOST_TEST_EQ(fs::canonical(relative_dir / "d1/../f0"), dir / "f0");
+ }
+
+ // canonical_symlink_tests -----------------------------------------------------------//
+
+ void canonical_symlink_tests()
+ {
+ cout << "canonical_symlink_tests..." << endl;
+
+ fs::path relative_dir(dir.filename());
+ BOOST_TEST_EQ(fs::canonical(dir / "sym-d1/f2"), d1 / "f2");
+ BOOST_TEST_EQ(fs::canonical(relative_dir / "sym-d1/f2"), d1 / "f2");
+ }
+
+ // copy_file_tests ------------------------------------------------------------------//
 
   void copy_file_tests(const fs::path& f1, const fs::path& d1)
   {
@@ -1761,6 +1814,7 @@
 
 int cpp_main(int argc, char* argv[])
 {
+
 // document state of critical macros
 #ifdef BOOST_POSIX_API
   cout << "BOOST_POSIX_API is defined\n";
@@ -1805,7 +1859,6 @@
   initial_tests();
   predicate_and_status_tests();
   exception_tests();
- platform_specific_tests();
   create_directory_tests();
   current_directory_tests();
   space_tests();
@@ -1840,11 +1893,13 @@
   create_symlink_tests();
   resize_file_tests();
   absolute_tests();
+ canonical_basic_tests();
   copy_file_tests(f1, d1);
   if (create_symlink_ok) // only if symlinks supported
   {
     symlink_status_tests();
     copy_symlink_tests(f1, d1);
+ canonical_symlink_tests();
   }
   iterator_status_tests(); // lots of cases by now, so a good time to test
 // dump_tree(dir);
@@ -1857,6 +1912,7 @@
   write_time_tests(dir);
   
   temp_directory_path_tests();
+ platform_specific_tests();
   
   cout << "testing complete" << endl;
 

Modified: branches/release/libs/filesystem/v3/test/path_unit_test.cpp
==============================================================================
--- branches/release/libs/filesystem/v3/test/path_unit_test.cpp (original)
+++ branches/release/libs/filesystem/v3/test/path_unit_test.cpp 2011-10-09 09:54:09 EDT (Sun, 09 Oct 2011)
@@ -43,6 +43,7 @@
 #include <boost/detail/lightweight_test.hpp>
 #include <boost/detail/lightweight_main.hpp>
 #include <boost/smart_ptr.hpp> // used constructor tests
+#include <boost/functional/hash.hpp>
 
 #include <iostream>
 #include <iomanip>
@@ -399,9 +400,12 @@
   {
     std::cout << "testing relationals..." << std::endl;
 
+ boost::hash<path> hash;
+
 # ifdef BOOST_WINDOWS_API
     // this is a critical use case to meet user expectations
     CHECK(path("c:\\abc") == path("c:/abc"));
+ CHECK(hash(path("c:\\abc")) == hash(path("c:/abc")));
 # endif
 
     const path p("bar");
@@ -431,6 +435,9 @@
     CHECK(L"baz" == p2);
     CHECK(wstring(L"baz") == p2);
 
+ CHECK(hash(p) == hash(p));
+ CHECK(hash(p) != hash(p2)); // Not strictly required, but desirable
+
     CHECK(!(p != p));
     CHECK(p != p2);
     CHECK(p2 != p);


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk