fs_review branch merged
[SVN r16593]
This commit is contained in:
parent
da5281c632
commit
fadc0fc63e
@ -18,7 +18,7 @@ Library Design</h1>
|
||||
<a href="#Requirements">Requirements</a><br>
|
||||
<a href="#Realities">Realities</a><br>
|
||||
<a href="#Rationale">Rationale</a><br>
|
||||
<a href="#Abandoned Designs">Abandoned Designs</a><br>
|
||||
<a href="#Abandoned_Designs">#Abandoned_Designs</a><br>
|
||||
<a href="#References">References</a></p>
|
||||
|
||||
<h2><a name="Introduction">Introduction</a></h2>
|
||||
@ -111,10 +111,10 @@ of choice..</p>
|
||||
<li>Avoid giving the illusion of portability where portability in fact does not
|
||||
exist.<br>
|
||||
<br>
|
||||
Rationale: Defining important behavior unspecified or "implementation defined" does a
|
||||
Rationale: Leaving important behavior unspecified or "implementation defined" does a
|
||||
great disservice to programmers using a library because it makes it appear
|
||||
that code relying on the behavior is portable, when in fact there is nothing
|
||||
at all portable about it. The only case where such under-specification is acceptable is when both users and implementors know from
|
||||
portable about it. The only case where such under-specification is acceptable is when both users and implementors know from
|
||||
other sources exactly what behavior is required, yet for some reason it isn't
|
||||
possible to specify it exactly.</li>
|
||||
</ul>
|
||||
@ -197,13 +197,16 @@ design decisions.</p>
|
||||
|
||||
<p>Several key insights went into the <i>path</i> class design:</p>
|
||||
<ul>
|
||||
<li>Decoupling the input formats, internal conceptual (<i>vector<string></i>
|
||||
<li>Decoupling of the input formats, internal conceptual (<i>vector<string></i>
|
||||
or other sequence)
|
||||
model, and output formats.</li>
|
||||
<li>Providing two input formats (generic and O/S specific) broke a major
|
||||
design deadlock.</li>
|
||||
<li>Providing several output formats solved another set of previously
|
||||
intractable problems.</li>
|
||||
<li>Several non-obvious functions (particularly decomposition and composition)
|
||||
are required to support portable code. (Peter Dimov, Thomas Witt, Glen
|
||||
Knowles, others.)</li>
|
||||
</ul>
|
||||
|
||||
<p>Error checking was a particularly difficult area. One key insight was that
|
||||
@ -212,7 +215,7 @@ Rather, the programmer must think out the question "What operating systems
|
||||
want this path to be portable to?" By providing support for several
|
||||
answers to that question, the Filesystem Library alerts programmers of the need
|
||||
to ask it in the first place.</p>
|
||||
<h2><a name="Abandoned Designs">Abandoned Designs</a></h2>
|
||||
<h2><a name="Abandoned_Designs">Abandoned Designs</a></h2>
|
||||
<h3>operations.hpp</h3>
|
||||
<p>Dietmar Kühl's original dir_it design and implementation supported
|
||||
wide-character file and directory names. It was abandoned after extensive
|
||||
@ -233,10 +236,11 @@ real code.</p>
|
||||
<p>Yet another set of convenience functions ( for example, <i>remove</i> with
|
||||
permissive, prune, recurse, and other options, plus predicate, and possibly
|
||||
other, filtering features) were abandoned because the details became both
|
||||
complex and contentious. What is left is a toolkit of low-level operations from
|
||||
which the user can create more complex convenience operations, plus a very small
|
||||
number of convenience functions which were found to be useful enough to justify
|
||||
inclusion.</p>
|
||||
complex and contentious.</p>
|
||||
|
||||
<p>What is left is a toolkit of low-level operations from which the user can
|
||||
create more complex convenience operations, plus a very small number of
|
||||
convenience functions which were found to be useful enough to justify inclusion.</p>
|
||||
|
||||
<h3>path.hpp</h3>
|
||||
|
||||
@ -284,7 +288,7 @@ Variable Considered Harmful</i>, ACM SIGPLAN Notices, 8, 2, 1973, pp. 23-34</p>
|
||||
<hr>
|
||||
<p>© Copyright Beman Dawes, 2002</p>
|
||||
<p>Revised
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->13 September, 2002<!--webbot bot="Timestamp" endspan i-checksum="39336" --></p>
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->11 December, 2002<!--webbot bot="Timestamp" endspan i-checksum="38505" --></p>
|
||||
|
||||
</body>
|
||||
|
||||
|
@ -3,43 +3,55 @@
|
||||
<img border="0" src="../../../c++boost.gif" align="center" width="277" height="86">Filesystem
|
||||
Do-list</h1>
|
||||
<ul>
|
||||
<li>Finish the probe program, and ask Boost people to run it on various O/S's.<br>
|
||||
<li>Docs for boost/filesystem/exception.hpp still needed!<br>
|
||||
</li>
|
||||
<li>Finish portability guide and checking functions. Get opinions on default, Boost, and other error checks. POSIX?
|
||||
Windows? Mac? ISO 6990?<br>
|
||||
<li>Windows: Some files seem to be poisoned to the point where you can't even
|
||||
do is_directory() on them with an access error. For example,
|
||||
pagefile.sys. Should directory_iterator ignore these files?<br>
|
||||
</li>
|
||||
<li>Cyclic paths:</li>
|
||||
<li>Windows: //share style paths need more analysis and test cases for system_complete()
|
||||
and complete(). Also, path_test cases at line 410 need review, correction.<br>
|
||||
</li>
|
||||
<li>Windows: What happens when a directory_itorator encounters a
|
||||
wide-character filename? Write a test case.<br>
|
||||
</li>
|
||||
<li>Windows: Resolve the current confusion between running on a POSIX O/S, and using
|
||||
the POSIX functions (via gcc) on Windows. This is the cause of the Win32 gcc
|
||||
regression test failure.<br>
|
||||
</li>
|
||||
<li>Links and cyclic paths:</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<ul>
|
||||
<li>General requirements.</li>
|
||||
<li>General requirements. How do links work on Windows and POSIX?</li>
|
||||
<li>Add cycle-breaking code if needed.</li>
|
||||
<li>Add test case to make sure functions like <i>remove_all</i> don't loop.</li>
|
||||
<li>Is a policy ctor needed for directory_iterator to deal with links?</li>
|
||||
<li>POSIX: lstat() or stat()?</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
<ul>
|
||||
<li>As a lexical concept, parent-directory is portable unless it escapes to
|
||||
the operating system. But do all operating recognize such a concept in a path?
|
||||
I doubt it. Maybe there should be a checking function that verifies that
|
||||
generic_path() contains no <code>".."</code>.<br>
|
||||
<li>Add "." current directory to generic path? Add test cases one
|
||||
way or the other. Change simple_ls accordingly.<br>
|
||||
</li>
|
||||
<li>Once the review is complete, ask for help porting to the Mac, etc.<br>
|
||||
</li>
|
||||
<li>From John Maddock:</li>
|
||||
<li>Ask for help porting to other operating systems, such as the Mac, etc.</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<pre>>All the functions generic_path, file_path, directory_path, leaf, and
|
||||
>branch,
|
||||
>are under-documented IMO. I had to read the specs quite closely before I
|
||||
>could figure out which did what. Adding examples to each would probably be
|
||||
>a help, or maybe a "description" section that provides a less terse
|
||||
>description than the standardese.</pre>
|
||||
</blockquote>
|
||||
<ul>
|
||||
<li>Change remove() to return a bool, now that the file doesn't have to
|
||||
exist.. (Keith Burton)</li>
|
||||
<li>Finish the probe program, and ask Boost people to run it on various O/S's.<br>
|
||||
</li>
|
||||
<li>Finish portability guide and checking functions. Get opinions on default, Boost, and other error checks. POSIX?
|
||||
Windows? Mac? ISO 6990? Document the checking functions.<br>
|
||||
</li>
|
||||
<li>Operations_test line 171 - why only check iterator tag? Why not
|
||||
Assignable, etc?<br>
|
||||
</li>
|
||||
<li>The wrapped fstream functions which return the type of the stream (*this)
|
||||
would have to be overridden to get the wrapped type (boost::filesystem::ifstream
|
||||
rather than std::ifstream, for example). But does it matter? Does anyone care?
|
||||
Will any programs fail?<br>
|
||||
</li>
|
||||
</ul>
|
||||
<hr>
|
||||
<p>© Copyright Beman Dawes, 2002</p>
|
||||
<p>Revised
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->22 September, 2002<!--webbot bot="Timestamp" endspan i-checksum="39335" --></p>
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->11 December, 2002<!--webbot bot="Timestamp" endspan i-checksum="38505" --></p>
|
65
doc/faq.htm
65
doc/faq.htm
@ -4,33 +4,42 @@
|
||||
<h1>
|
||||
<img border="0" src="../../../c++boost.gif" align="center" width="277" height="86">Filesystem
|
||||
FAQ</h1>
|
||||
<p><b>Why not use a URI (Universal Resource Identifier) based path?</b></p>
|
||||
<p>URI's would promise more than the Filesystem Library can actually deliver,
|
||||
since URI's extend far beyond what most operating systems consider a file or a
|
||||
directory. Thus for the primary "portable script-style file system
|
||||
operations" requirement of the Filesystem Library, full URI's appear to be over-specification.</p>
|
||||
<p><b>Why base the generic-path string format on POSIX?<br>
|
||||
<br>
|
||||
</b>POSIX is the basis for the most familiar path-string formats, including the
|
||||
<p><b>Why base the generic-path string format on POSIX?</b></p>
|
||||
<p>POSIX is the basis for the most familiar path-string formats, including the
|
||||
URL portion of URI's and the native Windows format. It is ubiquitous and
|
||||
familiar. On many systems, it is very easy to implement because it is
|
||||
either the native operating system format (Unix and Windows) or via a
|
||||
operating system supplied
|
||||
POSIX library (z/OS, OS/390, and many more.)</p>
|
||||
<p><b>Why not use a full URI (Universal Resource Identifier) based path?</b></p>
|
||||
<p>URI's would promise more than the Filesystem Library can actually deliver,
|
||||
since URI's extend far beyond what most operating systems consider a file or a
|
||||
directory. Thus for the primary "portable script-style file system
|
||||
operations" requirement of the Filesystem Library, full URI's appear to be over-specification.</p>
|
||||
<p><b>Why isn't <i>path</i> a base class with derived <i>directory_path</i> and
|
||||
<i>file_path</i> classes?</b></p>
|
||||
<p>Why bother? The behavior of all three classes is essentially identical.
|
||||
Several early versions did require users to identify each path as a file or
|
||||
directory path, and this seemed to increase errors and decrease code
|
||||
readability. There was no apparent upside benefit. </p>
|
||||
<p><b>Why not support a concept of specific kinds file systems, such as
|
||||
posix_file_system or windows_file_system.</b></p>
|
||||
<p><b>Why do some function names have a "native_" prefix?</b></p>
|
||||
<p>To alert users that the results are inherently non-portable. The names are
|
||||
deliberately ugly to discourage use except where really necessary.</p>
|
||||
<p><b>Why doesn't path supply operator== and other comparison operators?</b></p>
|
||||
<p>There is no way to know if two <i>path</i> objects actually represent the
|
||||
same path. For example, <i>path("/foo")</i> and <i>path("../foo")</i> may
|
||||
represent the same path, even though they are textually different. If exact
|
||||
textual comparison is desired, <i>
|
||||
path::string()'s</i> can be used.</p>
|
||||
<p><b>Why not support a concept of specific kinds of file systems, such as posix_file_system or windows_file_system.</b></p>
|
||||
<p>Portability is one of the one or two most important requirements for the
|
||||
library. Gaining some advantage by using features specific to particular
|
||||
operating systems is not a requirement.</p>
|
||||
library. Gaining some advantage by using features specific to particular
|
||||
operating systems is not a requirement. There doesn't appear to be much need for
|
||||
the ability to manipulate, say, a classic Mac OS path while running on an
|
||||
OpenVMS machine.</p>
|
||||
<p>Furthermore, concepts like "posix_file_system"
|
||||
are very slippery. What happens when a NTFS or ISO 9660 file system is mounted
|
||||
in directory on a machine running the POSIX operating system, for example?</p>
|
||||
in directory on a machine running a POSIX-like operating system, for example?</p>
|
||||
<p><b>Why not supply a 'handle' type, and let the file and directory operations
|
||||
traffic in it?</b></p>
|
||||
<p>It isn't clear there is any feasible way to meet the "portable script-style
|
||||
@ -121,11 +130,11 @@ system depend as to be disqualified as a "guaranteed presence" operati
|
||||
<p><b>Why isn't there a set_current_directory function?</b></p>
|
||||
<p>Global variables are considered harmful [<a href="design.htm#Wulf-Shaw-73">wulf-shaw-73</a>].
|
||||
While we can't prevent people from shooting themselves in the foot, we aren't
|
||||
about to hand them the gun.</p>
|
||||
about to hand them a loaded gun pointed right at their big toe.</p>
|
||||
<p><b>Why aren't there query functions for compound conditions like existing_directory?</b></p>
|
||||
<p>After several attempts, named queries for multi-attribute proved a
|
||||
slippery-slope; where do you stop?</p>
|
||||
<p><b>Why aren't <a name="wide-character names">wide-character names</a> supported? Why not std::wstring or even
|
||||
<p><b>Why aren't <a name="wide-character_names">wide-character names</a> supported? Why not std::wstring or even
|
||||
a templated type?</b></p>
|
||||
<p>Wide-character names would provide an illusion of portability where
|
||||
portability does not in fact exist. Behavior would be completely different on
|
||||
@ -141,6 +150,8 @@ between wide-character and narrow-character names for file systems which do not
|
||||
wide-character name, and
|
||||
(3) even the committee members most interested in wide-character names are
|
||||
unsure that they are a good idea in the context of a portable library.</p>
|
||||
<p>[October, 2002 - PJ Plauger has suggested a locale based conversion
|
||||
scheme. Others have indicated support for such an experiment.]</p>
|
||||
<p><b>Why aren't file and directory name portability errors detected automatically,
|
||||
rather than by separate function calls?</b></p>
|
||||
<p>Applications mix use of portable and non-portable names, and the situations
|
||||
@ -151,28 +162,10 @@ native directories and files for later use restricted to ISO-6990 filesystem,
|
||||
conditions for error are very different between the source and the target.</p>
|
||||
<p>A number (at least six) of designs for automatic name validity error
|
||||
detection were evaluated, including at least four complete implementations.
|
||||
While the details for rejection differed, they all tended to distort the
|
||||
While the details for rejection differed, all automatic name validity checking
|
||||
designs tended to distort the
|
||||
otherwise simple design of the rest of the library.</p>
|
||||
<p><b>Why doesn't the generic path grammar include syntax for portably
|
||||
specifying the root directory?</b></p>
|
||||
<p>The concept of "root directory" appears to be inherently non-portable.
|
||||
For example, "/" means one thing on POSIX (an absolute path the single
|
||||
filesystem root), and another on Windows (a relative path to the root of the
|
||||
current drive). It goes rapidly downhill from there; on the classic Mac
|
||||
OS, root names can be ambiguous!</p>
|
||||
<p><b>Why isn't there a path::is_absolute() or similar function?</b></p>
|
||||
<p>Because useful semantics are not obvious. On some operating systems a path is clearly either absolute or
|
||||
relative, but on others the distinction isn't clear. For example, on Windows consider these
|
||||
paths:</p>
|
||||
<ul>
|
||||
<li>"/foo" is not strictly an absolute path since it is relative to the
|
||||
current drive, yet appending it to another path as if it were relative clearly
|
||||
isn't correct.</li>
|
||||
<li>"c:foo" is relative to the current working directory on drive "c:",
|
||||
yet it can't be treated like other relative paths in that it can't be appended
|
||||
to an absolute path.</li>
|
||||
</ul>
|
||||
<hr>
|
||||
<p>© Copyright Beman Dawes, 2002</p>
|
||||
<p>Revised
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->12 September, 2002<!--webbot bot="Timestamp" endspan i-checksum="39334" --></p>
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->11 December, 2002<!--webbot bot="Timestamp" endspan i-checksum="38505" --></p>
|
177
doc/index.htm
177
doc/index.htm
@ -49,20 +49,20 @@ design</a> encourages, but does not require, safe and portable filesystem usage.
|
||||
directory boost/filesystem:</p>
|
||||
|
||||
<ul>
|
||||
<li>Header <i>path.hpp</i> provides class <i>path, </i>a portable mechanism for representing
|
||||
<li>Header <i><a href="../../../boost/filesystem/path.hpp">path.hpp</a></i> provides class <i>path, </i>a portable mechanism for representing
|
||||
<a href="#path">paths</a> in C++ programs. Validity checking
|
||||
functions are also provided. See <a href="path.htm">path.hpp documentation</a>.<br>
|
||||
</li>
|
||||
<li>Header <i>operations.hpp</i> provides functions operating on files and directories,
|
||||
<li>Header <i><a href="../../../boost/filesystem/operations.hpp">operations.hpp</a></i> provides functions operating on files and directories,
|
||||
and includes class <i>directory_iterator</i>. See <a href="operations.htm">
|
||||
operations.hpp documentation</a>.<br>
|
||||
</li>
|
||||
<li>Header <i>fstream.hpp</i> provides the same components as the C++ Standard
|
||||
<li>Header <i><a href="../../../boost/filesystem/fstream.hpp">fstream.hpp</a></i> provides the same components as the C++ Standard
|
||||
Library's <i>fstream</i> header, except
|
||||
that files are identified by <i>path</i> objects rather that <i>char *</i>'s.
|
||||
See <a href="fstream.htm">fstream.hpp documentation</a>.<br>
|
||||
</li>
|
||||
<li>Header <i>exception.hpp</i> provides class <i>filesystem_error</i>. See
|
||||
<li>Header <i><a href="../../../boost/filesystem/exception.hpp">exception.hpp</a></i> provides class <i>filesystem_error</i>. See
|
||||
<a href="exception.htm">exception.hpp documentation</a>.<br>
|
||||
</li>
|
||||
<li>Experimental header <i>
|
||||
@ -76,7 +76,7 @@ directory boost/filesystem:</p>
|
||||
<blockquote>
|
||||
<pre>#include "boost/filesystem/operations.hpp" // includes boost/filesystem/path.hpp
|
||||
#include "boost/filesystem/fstream.hpp" // ditto
|
||||
#include <iostream> // for cout
|
||||
#include <iostream> // for std::cout
|
||||
namespace fs = boost::filesystem;</pre>
|
||||
</blockquote>
|
||||
<p>A <a href="path.htm#synopsis">class <i>path</i></a> object can be created:</p>
|
||||
@ -103,19 +103,19 @@ if ( !fs::exists( "foobar/cheeze" ) )
|
||||
std::cout << "Something is rotten in foobar\n";</pre>
|
||||
</blockquote>
|
||||
<p>Additional class path constructors provide for an operating system dependent
|
||||
format, useful for with user provided input:</p>
|
||||
format, useful for user provided input:</p>
|
||||
<blockquote>
|
||||
<pre>int main( int argc, char * argv[] ) {
|
||||
fs::path arg_path( argv[1], fs::system_specific );</pre>
|
||||
fs::path arg_path( argv[1], fs::native ); // native means use O/S path format</pre>
|
||||
</blockquote>
|
||||
<p>To make class <i>path</i> objects easy to use in expressions, <i>operator<<</i>
|
||||
<p>To make class <i>path</i> objects easy to use in expressions, <i>operator/</i>
|
||||
appends paths:</p>
|
||||
<blockquote>
|
||||
<pre>fs::ifstream file1( arg_path << "foo/bar" );
|
||||
fs::ifstream file2( arg_path << "foo" << "bar" );</pre>
|
||||
<pre>fs::ifstream file1( arg_path / "foo/bar" );
|
||||
fs::ifstream file2( arg_path / "foo" / "bar" );</pre>
|
||||
</blockquote>
|
||||
<p>Note that expressions <i>arg_path << "foo/bar"</i> and <i>arg_path << "foo"
|
||||
<< "bar"</i> yield equivalent results.</p>
|
||||
<p>Note that expressions <i>arg_path / "foo/bar"</i> and <i>arg_path / "foo"
|
||||
/ "bar"</i> yield identical results.</p>
|
||||
<p><a href="operations.htm#Class directory_iterator">Class <i>directory_iterator</i></a>
|
||||
is an important component of the library. It provides input iterators over the
|
||||
contents of a directory, with the value type being class <i>path</i>.</p>
|
||||
@ -161,10 +161,30 @@ checking code.</p>
|
||||
<p>The tutorial is now over; hopefully you now are ready to write simple,
|
||||
script-like, programs using the Filesystem Library!</p>
|
||||
<h2><a name="Examples">Examples</a></h2>
|
||||
<p>Until a custom-made example is available, see
|
||||
<a href="../example/compiler_status.cpp">compiler_status.cpp</a>, an actual
|
||||
program which uses the library.</p>
|
||||
<p>Test programs are also sometimes useful in understanding a library, as they
|
||||
<h3>simple_ls.cpp</h3>
|
||||
<p>The example program <a href="../example/simple_ls.cpp">simple_ls.cpp</a> is
|
||||
given a path as a command line argument. Since the command line argument may be
|
||||
a relative path, the complete path is determined so that messages displayed
|
||||
can be more precise.</p>
|
||||
<p>The program checks to see if the path exists; if not a message is printed.</p>
|
||||
<p>If the path identifies a directory, the directory is iterated through,
|
||||
printing the name of the entries found, and an indication if they are
|
||||
directories. A count of directories and files is updated, and then printed after
|
||||
the iteration is complete.</p>
|
||||
<p>If the path is for a file, a message indicating that is printed.</p>
|
||||
<p>Try compiling and executing <a href="../example/simple_ls.cpp">simple_ls.cpp</a>
|
||||
to see how it works on your system. Try various path arguments to see what
|
||||
happens.</p>
|
||||
<h3>Other examples</h3>
|
||||
<p>The programs used to generate the Boost regression test status tables use the
|
||||
Filesystem Library extensively. See:</p>
|
||||
<ul>
|
||||
<li><a href="../../../tools/regression/process_jam_log.cpp">
|
||||
process_jam_log.cpp</a></li>
|
||||
<li><a href="../../../tools/regression/compiler_status.cpp">
|
||||
compiler_status.cpp</a></li>
|
||||
</ul>
|
||||
<p>Test programs are sometimes useful in understanding a library, as they
|
||||
illustrate what the developer expected to work and not work. See:</p>
|
||||
<ul>
|
||||
<li><a href="../test/path_test.cpp">path_test.cpp</a></li>
|
||||
@ -175,7 +195,7 @@ illustrate what the developer expected to work and not work. See:</p>
|
||||
<p><b><a name="directory">directory</a> </b>- A container provided by the operating system,
|
||||
containing the names of files, other directories, or both. Directories are identified
|
||||
by <a href="#directory path">directory path</a>.</p>
|
||||
<p><b><a name="directory tree">directory tree</a></b> - A directory and file
|
||||
<p><b><a name="directory_tree">directory tree</a></b> - A directory and file
|
||||
hierarchy viewed as an acyclic graph.</p>
|
||||
<p><b><a name="path">path</a> </b>- A possibly empty sequence of names. Each
|
||||
element in the sequence, except the last, names a <a href="#directory">directory</a>
|
||||
@ -189,7 +209,7 @@ defined syntax distinguishes between the name elements. Other representations of
|
||||
a path are possible, such as each name being an element in a <code>std::vector<std::string></code>.</p>
|
||||
<p><b><a name="file path">file path</a></b> - A <a href="#path">path</a> whose
|
||||
last element is a file.</p>
|
||||
<p><b><a name="directory path">directory path</a></b> - A <a href="#path">path</a>
|
||||
<p><b><a name="directory_path">directory path</a></b> - A <a href="#path">path</a>
|
||||
whose last element is a directory.</p>
|
||||
<p><b><a name="name">name</a></b> - A file or directory name, without any
|
||||
<a href="#directory path">directory path</a> information to indicate the file or
|
||||
@ -246,42 +266,121 @@ either the POSIX or Windows API's available.</p>
|
||||
<li><a href="../test/operations_test.cpp">operations_test.cpp</a></li>
|
||||
<li><a href="../test/fstream_test.cpp">fstream_test.cpp</a></li>
|
||||
</ul>
|
||||
<p>As of September, 2002, these tests succeed for the following compilers on Windows:</p>
|
||||
<p>As of December, 2002, these tests succeed for the following compilers on Windows:</p>
|
||||
<ul>
|
||||
<li>Borland 5.5.1</li>
|
||||
<li>Borland 5.6</li>
|
||||
<li>GCC 3.1 (using POSIX implementation, but excluding wide-character fstream tests)</li>
|
||||
<li>Intel 6.0</li>
|
||||
<li>Metrowerks 8.2</li>
|
||||
<li>Metrowerks 8.3</li>
|
||||
<li>Microsoft 7.0</li>
|
||||
<li>Microsoft 6.0 except fstream_test failed.</li>
|
||||
</ul>
|
||||
<p>As of September, 2002, some limited use has been successful on Linux using
|
||||
GCC and IBM/AIX using Visual Age C++.</p>
|
||||
<p>As of December, 2002, limited use has been successful on Linux using GCC and IBM/AIX using Visual Age C++.</p>
|
||||
<h2><a name="Acknowledgements">Acknowledgements</a></h2>
|
||||
<p>The Filesystem Library was designed and implemented by Beman Dawes, except
|
||||
for the <i>directory_iterator</i> and <i>filesystem_error</i> classes which were
|
||||
based on prior work from Dietmar Kühl, as modified by Jan Langer.</p>
|
||||
<p>The Filesystem Library was designed and implemented by Beman Dawes. The <i>directory_iterator</i> and <i>filesystem_error</i> classes were
|
||||
based on prior work from Dietmar Kühl, as modified by Jan Langer. Thomas Witt
|
||||
was a particular help in later stages of development.</p>
|
||||
|
||||
<p>Key <a href="design.htm#Requirements">design requirements</a> and
|
||||
<a href="design.htm#Realities">design realities</a> were developed during extensive discussions on the Boost mailing list,
|
||||
followed by comments on the actual implementation. Participants included
|
||||
(in more-or-less chronological order) Beman Dawes, Jan Langer, Darin Adler, Michiel
|
||||
Salters, Jani Kajala, Jason Stewart, Carl Daniel, David Abrahams, Bill Kempf,
|
||||
Jonathan Caves, George Heintzelman, Ken Hagen, Eric Jensen, Joel de Guzman, Jim
|
||||
Hyslop, John Maddock, Matt Austern, Peter Dimov, Davlet Panech, Dylan Nicholson, Tom Harris,
|
||||
Giovanni Bajo, Baptiste Lepilleur, Thomas Witt, Keith Burton, Mattias Flodin,
|
||||
Daniel Frey, Vladimir Prus, Toon Knapen.</p>
|
||||
|
||||
<p>Specific improvements for a preliminary design document came from Dan Nuffer and Jeff
|
||||
Garland.</p>
|
||||
|
||||
<a href="design.htm#Realities">design realities</a> were developed during
|
||||
extensive discussions on the Boost mailing list, followed by comments on the
|
||||
initial implementation. Numerous helpful comments were then received during the
|
||||
Formal Review.<p>Participants included
|
||||
Aaron Brashears,
|
||||
Alan Bellingham,
|
||||
Aleksey Gurtovoy,
|
||||
Alex Rosenberg,
|
||||
Alisdair Meredith,
|
||||
Andy Glew,
|
||||
Anthony Williams,
|
||||
Baptiste Lepilleur,
|
||||
Beman Dawes,
|
||||
Bill Kempf,
|
||||
Bill Seymour,
|
||||
Carl Daniel,
|
||||
Chris Little,
|
||||
Chuck Allison,
|
||||
Craig Henderson,
|
||||
Dan Nuffer,
|
||||
Dan'l Miller,
|
||||
Daniel Frey,
|
||||
Darin Adler,
|
||||
David Abrahams,
|
||||
David Held,
|
||||
Davlet Panech,
|
||||
Dietmar Kuehl,
|
||||
Douglas Gregor,
|
||||
Dylan Nicholson,
|
||||
Ed Brey,
|
||||
Eric Jensen,
|
||||
Eric Woodruff,
|
||||
Fedder Skovgaard,
|
||||
Gary Powell,
|
||||
Gennaro Prota,
|
||||
Geoff Leyland,
|
||||
George Heintzelman,
|
||||
Giovanni Bajo,
|
||||
Glen Knowles,
|
||||
Hillel Sims,
|
||||
Howard Hinnant,
|
||||
Jaap Suter,
|
||||
James Dennett,
|
||||
Jan Langer,
|
||||
Jani Kajala,
|
||||
Jason Stewart,
|
||||
Jeff Garland,
|
||||
Jens Maurer,
|
||||
Jesse Jones,
|
||||
Jim Hyslop,
|
||||
Joel de Guzman,
|
||||
Joel Young,
|
||||
John Levon,
|
||||
John Maddock,
|
||||
John Williston,
|
||||
Jonathan Caves,
|
||||
Jonathan Biggar,
|
||||
Jurko,
|
||||
Justus Schwartz,
|
||||
Keith Burton,
|
||||
Ken Hagen,
|
||||
Kostya Altukhov,
|
||||
Mark Rodgers,
|
||||
Martin Schuerch,
|
||||
Matt Austern,
|
||||
Matthias Troyer,
|
||||
Mattias Flodin,
|
||||
Michiel Salters,
|
||||
Mickael Pointier,
|
||||
Misha Bergal,
|
||||
Neal Becker,
|
||||
Noel Yap,
|
||||
Parksie,
|
||||
Patrick Hartling,
|
||||
Pete Becker,
|
||||
Peter Dimov,
|
||||
Rainer Deyke,
|
||||
Rene Rivera,
|
||||
Rob Lievaart,
|
||||
Rob Stewart,
|
||||
Ron Garcia,
|
||||
Ross Smith,
|
||||
Sashan,
|
||||
Steve Robbins,
|
||||
Thomas Witt,
|
||||
Tom Harris,
|
||||
Toon Knapen,
|
||||
Victor Wagner,
|
||||
Vincent Finn,
|
||||
Vladimir Prus, and
|
||||
Yitzhak Sapir
|
||||
|
||||
<p>A lengthy discussion on the C++ committee's library reflector illuminated the "illusion
|
||||
of portability" problem, particularly in postings by JP Plauger and Pete Becker.</p>
|
||||
|
||||
<hr>
|
||||
<p>© Copyright Beman Dawes, 2002</p>
|
||||
<p>Revised
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->13 September, 2002<!--webbot bot="Timestamp" endspan i-checksum="39336" --></p>
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->11 December, 2002<!--webbot bot="Timestamp" endspan i-checksum="38505" --></p>
|
||||
|
||||
</body>
|
||||
|
||||
|
@ -15,11 +15,11 @@
|
||||
|
||||
<p><a href="#Introduction">Introduction</a><br>
|
||||
<a href="#Synopsis">Header synopsis</a><br>
|
||||
<a href="#Class directory_iterator">Class directory_iterator</a><br>
|
||||
<a href="#directory_iterator">Class directory_iterator</a><br>
|
||||
<a href="#constructors">Constructors</a><br>
|
||||
<a href="#destructor">Destructor</a><br>
|
||||
<a href="#other functions">Other functions</a><br>
|
||||
<a href="#Non-member functions">Non-member functions</a><br>
|
||||
<a href="#Other_functions">Other_functions</a><br>
|
||||
<a href="#Non-member_functions">Operations functions</a><br>
|
||||
<a href="#exists">exists</a><br>
|
||||
<a href="#is_directory">is_directory</a><br>
|
||||
<a href="#is_empty">is_empty</a><br>
|
||||
@ -74,27 +74,31 @@ exceptions being thrown. See <a href="index.htm#Requirements">Requirements</a>.<
|
||||
bool <a href="#is_empty">is_empty</a>( const path & ph );
|
||||
|
||||
void <a href="#create_directory">create_directory</a>( const path & directory_ph );
|
||||
void <a href="#remove">remove</a>( const path & ph );
|
||||
bool <a href="#remove">remove</a>( const path & ph );
|
||||
unsigned long <a href="#remove_all">remove_all</a>( const path & ph );
|
||||
void <a href="#rename">rename</a>( const path & from_path,
|
||||
const path & to_path );
|
||||
void <a href="#copy_file">copy_file</a>( const path & from_file_ph,
|
||||
const path & to_file_ph );
|
||||
|
||||
const path & <a href="#initial_directory">initial_directory</a>();
|
||||
const path & <a href="#initial_path">initial_path</a>();
|
||||
path <a href="#current_path">current_path</a>();
|
||||
path <a href="#complete">complete</a>( const path & ph,
|
||||
const path & base = initial_path() );
|
||||
path <a href="#system_complete">system_complete</a>( const path & ph );
|
||||
|
||||
} // namespace filesystem
|
||||
} // namespace boost
|
||||
</pre>
|
||||
|
||||
<h2><a name="Class directory_iterator">Class directory_iterator</a></h2>
|
||||
<h2><a name="directory_iterator">Class directory_iterator</a></h2>
|
||||
|
||||
<p>Class <i>directory_iterator</i> provides a C++ standard conforming input
|
||||
iterator which accesses the contents of a <a href="reference.htm#directory">
|
||||
iterator which accesses the contents of a <a href="index.htm#directory">
|
||||
directory</a>. </p>
|
||||
|
||||
<p>The value type is <i><a href="path.htm">boost::filesystem::path</a></i>, so
|
||||
dereferencing a <i>directory_iterator</i> yields a <a href="reference.htm#path">
|
||||
dereferencing a <i>directory_iterator</i> yields a <a href="index.htm#path">
|
||||
path</a> to a file or directory contained within the directory represented by
|
||||
the directory-path argument supplied at construction. The path returned by
|
||||
dereferencing a <i>directory_iterator</i> is composed by appending the name of
|
||||
@ -134,13 +138,13 @@ representing the first path in <i>directory_ph</i>, or if <code>
|
||||
empty(directory_ph)</code>, the <i>past-the-end</i> value.</p>
|
||||
</blockquote>
|
||||
|
||||
<h3><a name="other functions">Other functions</a></h3>
|
||||
<h3><a name="Other_functions">Other functions</a></h3>
|
||||
|
||||
<p>Class <i>directory_iterator</i> also supplies all the other functions
|
||||
required by the C++ standard clause 24 for input iterators, such as <i>operator==</i>,
|
||||
<i>operator++</i>, and <i>operator*</i>.</p>
|
||||
|
||||
<h2><a name="Non-member functions">Non-member functions</a></h2>
|
||||
<h2><a name="Non-member_functions">Non-member functions</a></h2>
|
||||
|
||||
<p>
|
||||
The non-member functions provide common operations on files and directories.
|
||||
@ -213,7 +217,9 @@ is_directory(directory_ph) && is_empty(directory_ph)</code></p>
|
||||
</blockquote>
|
||||
<h3><a name="remove">remove</a></h3>
|
||||
<blockquote>
|
||||
<p><code>void remove( const path & ph );</code></p>
|
||||
<p><code>bool remove( const path & ph );</code></p>
|
||||
<p><b>Returns:</b> The value of <code>exists( ph )</code> prior to the
|
||||
establishment of the postcondition. </p>
|
||||
<p><b>Postcondition:</b> <code>!exists( ph )</code></p>
|
||||
<p><b>Throws:</b> if<code> exists(ph) && is_directory(ph) && !is_empty(ph)</code></p>
|
||||
<p><b>Rationale:</b> Does not throw when <code>!exists( ph )</code> because not
|
||||
@ -227,8 +233,8 @@ throwing is:</p>
|
||||
<p>There is, however, a slight decrease in safety because some errors will slip
|
||||
by which otherwise would have been detected. For example, a misspelled path name
|
||||
could go undetected for a long time.</p>
|
||||
<p>The initial version of the library did throw when the path did not exist; it
|
||||
was changed only reluctantly.</p>
|
||||
<p>The initial version of the library threw and exception when the path did not exist; it
|
||||
was reluctantly changed to reflect user complaints.</p>
|
||||
</blockquote>
|
||||
<h3><a name="remove_all">remove_all</a></h3>
|
||||
<blockquote>
|
||||
@ -267,31 +273,144 @@ to_file_ph</i>.</p>
|
||||
<p><b>Throws:</b> if <code>!exists(from_file_ph) || directory(from_file_ph)
|
||||
|| exists(to_file_ph) || !exist(branch(to_path))</code></p>
|
||||
</blockquote>
|
||||
<h3><a name="initial_directory">initial_directory</a></h3>
|
||||
<h3><a name="initial_path">initial_path</a></h3>
|
||||
<blockquote>
|
||||
<p><code>const path & initial_directory();</code></p>
|
||||
<p><b>Effects:</b> The first time the function is called, stores an absolute
|
||||
directory path.</p>
|
||||
<p>The preferred value for the stored path is the initial working directory path when <i>
|
||||
main()</i> was called. Implementations are permitted, however, to store the
|
||||
current working directory at the time of the first call to <i>initial_directory()</i>. If neither of these actions is possible, a diagnostic
|
||||
is required.</p>
|
||||
<p><b>Returns:</b> The stored path.</p>
|
||||
<p><b>Rationale:</b> The semantics, in effect, turn a global variable into
|
||||
<p><code>const path & initial_path();</code></p>
|
||||
<p><b>Effects:</b> The first time called, stores the path returned by
|
||||
<a href="#current_path">current_path()</a>.</p>
|
||||
<p>The preferred implementation is to call <i>initial_path()</i> during program
|
||||
initialization, before the call to main().</p>
|
||||
<p><b>Returns:</b> A reference to the stored path.</p>
|
||||
<p><b>Rationale:</b> The semantics, in effect, turn a dangerous global variable into
|
||||
a safer global constant. The preferred implementation requires runtime library
|
||||
support, so alternate semantics are supplied for those implementations which
|
||||
cannot change an existing the runtime library.</p>
|
||||
<p><b>Note:</b> It would be good practice in a program dependent on <i>
|
||||
initial_directory()</i> to call it immediately upon entering<i> main()</i>. That
|
||||
<p><b>Note:</b> It is good practice for a program dependent on <i>
|
||||
initial_path()</i> to call it immediately upon entering<i> main()</i>. That
|
||||
protects against another function altering the current working
|
||||
directory (using a native platform function) before the first call to <i>
|
||||
initial_directory()</i>.</p>
|
||||
initial_path()</i>.</p>
|
||||
|
||||
</blockquote>
|
||||
<h3><a name="current_path">current_path</a></h3>
|
||||
<blockquote>
|
||||
<pre>path current_path();</pre>
|
||||
<p><b>Returns:</b> The current path as maintained by the operating system.</p>
|
||||
<p><b>Postcondition:</b> <code>current_path().is_complete()</code></p>
|
||||
<p><b>Warning:</b> The current path maintained by the operating system is
|
||||
in-effect a dangerous global variable. It may be changed unexpectedly by a
|
||||
third-party or system library function, or by another thread. For a safer
|
||||
alternative, see <a href="#initial_path">initial_path()</a>.</p>
|
||||
<p><b>Rationale:</b> Although dangerous, the function is useful in dealing
|
||||
with other libraries.</p>
|
||||
</blockquote>
|
||||
<h3><a name="complete">complete</a></h3>
|
||||
|
||||
<blockquote>
|
||||
<p><code>path complete( const path & ph, const path & base = initial_path() );</code></p>
|
||||
|
||||
<p><b>Precondition:</b> <code>base.is_complete() && (ph.is_complete() || !ph.has_root_name())</code></p>
|
||||
|
||||
<p><b>Effects:</b> Composes a complete path from <code>ph</code> and <code>base</code>,
|
||||
using the following rules:</p>
|
||||
|
||||
<p>For single-root systems (POSIX-like systems, for example), if <code>ph.empty()</code>
|
||||
or <code>ph.is_complete()</code>, the composed path is <code>ph</code>,
|
||||
otherwise the composed path is <code>base/ph</code>.</p>
|
||||
|
||||
<p>For multi-root systems (Windows, Classic Mac, many others), the rules are
|
||||
give by this table:</p>
|
||||
<table border="1" cellpadding="5">
|
||||
<tr>
|
||||
<td align="center"> </td>
|
||||
<td align="center"><code>ph.has_root_directory()</code></td>
|
||||
<td align="center"><code>!ph.has_root_directory()</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><code>ph.has_root_name()</code></td>
|
||||
<td align="center"><code>ph</code></td>
|
||||
<td align="center"><code>(precondition failure)</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><code>!ph.has_root_name()</code></td>
|
||||
<td align="center"><code>base.root_name()<br>
|
||||
/ ph</code></td>
|
||||
<td align="center"><code>base / ph</code></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p><b>Returns:</b> The composed path.</p>
|
||||
|
||||
<p><b>Postcondition:</b> For the returned path, <code>p</code>; if <code>p.empty()</code>
|
||||
then <code>p.is_complete()</code> is false, otherwise <code>p.is_complete()</code>
|
||||
is true.</p>
|
||||
|
||||
<p><b><a name="complete_note">Note</a>:</b> When portable behavior is required,
|
||||
use <i>complete()</i>. When operating system dependent behavior is required, use
|
||||
<i>system_complete()</i>.</p>
|
||||
|
||||
<p>Portable behavior is preferred when dealing with paths created internally
|
||||
within a program, particularly where the program should exhibit the same
|
||||
behavior on all operating systems.</p>
|
||||
|
||||
<p>Operating system dependent behavior is preferred when dealing with paths
|
||||
supplied by user input, reported to program users, or which should result in
|
||||
program behavior familiar to and expected by program users. The
|
||||
<a href="../example/simple_ls.cpp">simple_ls.cpp</a> program, for example,
|
||||
operates on a path supplied in the native operating system format, so uses
|
||||
<i>system_complete()</i> to ensure that the path behaves as expected for the
|
||||
particular operating system.</p>
|
||||
|
||||
<p><b>Rationale:</b> The <code>!ph.has_root_name()</code> portion of the
|
||||
precondition disallows the error condition of <code>ph.root_name()</code>
|
||||
being not equivalent to <code>base.root_name()</code>. The restriction is
|
||||
broader that would appear necessary, in that is also prohibits the case where
|
||||
they are equivalent. There is, however, no portable way to express the
|
||||
root_name() equivalence requirement.</p>
|
||||
|
||||
</blockquote>
|
||||
<h3><a name="system_complete">system_complete</a></h3>
|
||||
|
||||
<blockquote>
|
||||
<p><code>path system_complete( const path & ph );</code></p>
|
||||
|
||||
<p><b>Effects:</b> Composes a complete path from <code>ph</code>, using the same
|
||||
rules used by the operating system to resolve a path passed as the filename
|
||||
argument to standard library open functions.</p>
|
||||
|
||||
<p>For POSIX-like systems, system_complete( ph ) has the same semantics as <code>
|
||||
complete( ph, current_path() )</code>.</p>
|
||||
|
||||
<p><a name="windows_effects">For Widows</a>, system_complete( ph ) has the same
|
||||
semantics as <code>complete( ph, current_path() )</code> if ph.is_complete() ||
|
||||
!ph.has_root_name() or ph and base have the same root_name().
|
||||
Otherwise it acts like <code>complete( ph, kinky )</code>, where <code>kinky</code>
|
||||
is the current directory for the <code>ph.root_name()</code> drive. This
|
||||
will be the current directory of that drive the last time it was set, and thus
|
||||
may well be <b>residue left over from some prior program</b> run by the command
|
||||
processor! Although these semantics are often useful, they are also very
|
||||
error-prone, and certainly deserve to be called "kinky".</p>
|
||||
|
||||
<p><b>Returns:</b> The composed path.</p>
|
||||
|
||||
<p><b>Postcondition:</b> For the returned path, <code>p</code>; if <code>p.empty()</code>
|
||||
then <code>p.is_complete()</code> is false, otherwise <code>p.is_complete()</code>
|
||||
is true.</p>
|
||||
|
||||
<p><b>Note:</b> See <a href="#complete_note"><i>complete()</i> note</a> for
|
||||
usage suggestions.</p>
|
||||
|
||||
<p><b>Warning:</b> This function relies on a global variable (current_path()),
|
||||
and so tends to be more error-prone than the similar function
|
||||
<a href="#complete">complete()</a>. This function is doubly dangerous on
|
||||
Windows, where under cross-drive conditions it may be relying on a directory set
|
||||
by a prior program run by the command processor.</p>
|
||||
|
||||
</blockquote>
|
||||
|
||||
<hr>
|
||||
<p>© Copyright Beman Dawes, 2002</p>
|
||||
<p>Revised
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->22 September, 2002<!--webbot bot="Timestamp" endspan i-checksum="39335" --></p>
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->11 December, 2002<!--webbot bot="Timestamp" endspan i-checksum="38505" --></p>
|
||||
|
||||
</body>
|
||||
|
||||
|
644
doc/path.htm
644
doc/path.htm
@ -20,12 +20,14 @@
|
||||
<a href="#synopsis">Header synopsis</a><br>
|
||||
<a href="#Class path">Class path</a><br>
|
||||
<a href="#Member">Member functions</a><br>
|
||||
<a href="#Non-member functions">Non-member functions</a></p>
|
||||
<a href="#Non-member functions">Non-member functions</a><br>
|
||||
<a href="#Validity_checking">Validity checking functions</a><br>
|
||||
<a href="#Rationale">Rationale</a><br>
|
||||
<a href="#decomposition">Path decomposition examples</a></p>
|
||||
<h2><a name="Introduction">Introduction</a></h2>
|
||||
|
||||
<p>Many Filesystem Library functions traffic in objects of class <i>path</i>,
|
||||
provided by this header. Non-member functions for error checking are also
|
||||
supplied.</p>
|
||||
<p>Filesystem Library functions traffic in objects of class <i>path</i>,
|
||||
provided by this header. The header also supplies non-member functions for error checking.</p>
|
||||
|
||||
<p>For actual operations on files and directories, see <a href="operations.htm">
|
||||
boost/filesystem/operations.hpp documentation</a>.</p>
|
||||
@ -36,17 +38,19 @@ documentation</a>.</p>
|
||||
<p>As with all Filesystem Library components, errors may result in <i>
|
||||
<a href="exception.htm">filesystem_error</a></i> or <i>std::bad_alloc</i>
|
||||
exceptions being thrown. See <a href="index.htm#Requirements">Requirements</a>.</p>
|
||||
<h2><a name="Class path">Class path</a></h2>
|
||||
<h2><a name="Class_path">Class path</a></h2>
|
||||
<p>Class <i>path</i> provides for portable mechanism for representing
|
||||
<a href="index.htm#path">paths</a> in C++ programs. Class <i>path</i>
|
||||
is concerned with the lexical and syntactic aspects of a path, regardless of
|
||||
whether or not such a path currently exists in the operating system's
|
||||
filesystem. </p>
|
||||
<p><b>Rationale:</b> If filesystem functions trafficked in <i>std::strings</i> or C-style strings, the
|
||||
<a href="index.htm#path">paths</a> in C++ programs, using a portable generic
|
||||
path string <a href="#Grammar">grammar</a>. Class <i>path</i>
|
||||
is concerned with the lexical and syntactic aspects of a path. The path does not
|
||||
have to exist in the operating system's
|
||||
filesystem, and may contain names which are not even valid for the current
|
||||
operating system. </p>
|
||||
<p><b>Rationale:</b> If Filesystem functions trafficked in <i>std::strings</i> or C-style strings, the
|
||||
functions
|
||||
would provide only an illusion of portability since the function calls would be
|
||||
portable but the strings they operate on would not be portable.</p>
|
||||
<h2><a name="Conceptual model">Conceptual model</a> of a path</h2>
|
||||
<h2>Conceptual <a name="model">model</a> of a path</h2>
|
||||
<p>An object of class <i>path</i> can be conceptualized as containing a sequence
|
||||
of strings, where each string contains the name of a directory, or, in the case
|
||||
of the string representing the element farthest from the root in the directory
|
||||
@ -55,7 +59,8 @@ hierarchy, the name of a directory or file. Such a path representation is
|
||||
independent of any particular representation of the path as a single
|
||||
string.</p>
|
||||
<p>There is no requirement that an implementation of class <i>path</i> actually
|
||||
contain a sequence of strings, but conceptualizing the contents that way provides
|
||||
contain a sequence of strings, but conceptualizing the contents as a sequence of
|
||||
strings provides
|
||||
a completely portable way to reason about paths.</p>
|
||||
<p>So that programs can portably express paths as a single string, class <i>path</i>
|
||||
defines a <a href="#Grammar">grammar</a> for a portable generic path string
|
||||
@ -68,43 +73,47 @@ constructor is provided which takes a system-specific format as an argument.</p>
|
||||
the operating system's format, and a file path string using the operating
|
||||
system's format. Additional access functions retrieve specific portions of
|
||||
the contained path.</p>
|
||||
<p></p>
|
||||
<p></p>
|
||||
<p></p>
|
||||
<p></p>
|
||||
<p></p>
|
||||
<p></p>
|
||||
<h2><a name="Grammar">Grammar</a> for portable generic path string</h2>
|
||||
<h2><a name="Grammar">Grammar</a> for portable generic path strings</h2>
|
||||
<p>The grammar is specified in extended BNF, with terminal symbols in quotes:
|
||||
</p>
|
||||
<blockquote>
|
||||
<pre>path ::= [system-specific-root] [relative-path] </pre>
|
||||
<pre>relative-path ::= element { "/" element } </pre>
|
||||
<pre>element ::= name | parent-directory </pre>
|
||||
<pre>path ::= [root] [relative-path] // an empty path is valid</pre>
|
||||
<pre>root ::= [root-name] [root-directory]</pre>
|
||||
<pre>root-directory ::= "/"</pre>
|
||||
<pre>relative-path ::= path-element { "/" path-element } ["/"]</pre>
|
||||
<pre>path-element ::= name | parent-directory </pre>
|
||||
<pre>parent-directory ::= ".." </pre>
|
||||
<pre>name ::= char { char }</pre>
|
||||
</blockquote>
|
||||
<p><i>system-specific-root</i> grammar is implementation-defined. <i>
|
||||
system-specific-root</i> must not be present in generic input (the undecorated
|
||||
<p>The following are not valid name <i>char</i>'s: <code>x01-x1F, <, >, :, ", /,
|
||||
\, |, *, ?</code>. Although these characters are supported by some operating
|
||||
systems, they are disallowed by so many operating systems that they are banned
|
||||
altogether.</p>
|
||||
<p><i>root-name</i> grammar is implementation-defined. <i>
|
||||
root-name</i> must not be present in generic input (the undecorated
|
||||
<i>path</i> constructors); it may be part of the strings returned by <i>path</i>
|
||||
member functions, and may be present in the argument to <i>path</i> constructors
|
||||
with the <i><a href="#system_specific">system_specific</a></i> decorator.</p>
|
||||
with the <i><a href="#native">native</a></i> decorator.</p>
|
||||
<p>Although implementation-defined, it is desirable that <i>
|
||||
system-specific-root</i> have a grammar which is distinguishable from other grammar elements,
|
||||
root-name</i> have a grammar which is distinguishable from other grammar elements,
|
||||
and follow the conventions of the operating system.</p>
|
||||
<p>The optional trailing "/" in a <i>relative-path</i> is allowed as a
|
||||
notational convenience. It has no semantic meaning and is discarded in
|
||||
conversions to <a href="#Canonical">canonical form</a>.</p>
|
||||
<p>Whether or not a generic path string is actually portable to a particular
|
||||
operating system will depend on the
|
||||
names used. See the <a href="portability_guide.htm">Portability Guide</a>.</p>
|
||||
<h2><a name="Canonical">Canonical</a> form</h2>
|
||||
<p>Adjacent <i>name, parent-directory</i> elements in <code>m_name</code>
|
||||
have been recursively removed. </p>
|
||||
<p>Adjacent <i>name, parent-directory</i> elements in <code>m_name</code> are recursively removed.</p>
|
||||
<p> <i>relative-path</i> does not have a trailing
|
||||
"/".</p>
|
||||
<h2>Header <a href="../../../boost/filesystem/path.hpp">
|
||||
boost/filesystem/path.hpp</a> <a name="synopsis">synopsis</a></h2>
|
||||
<pre>namespace boost
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
enum path_format { <a name="system_specific">system_specific</a> };
|
||||
enum path_format { <a name="native">native</a> };
|
||||
|
||||
class path
|
||||
{
|
||||
@ -120,47 +129,54 @@ boost/filesystem/path.hpp</a> <a name="synopsis">synopsis</a></h2>
|
||||
<a href="#constructors">path</a>( const char * src, path_format );
|
||||
|
||||
// append operations:
|
||||
path & <a href="#operator-shift-equal">operator<<=</a>( const path & rhs );
|
||||
const path <a href="#operator-shift">operator<<</a>( const path & rhs ) const;
|
||||
path & <a href="#operator_slash_equal">operator /=</a> ( const path & rhs );
|
||||
path <a href="#operator_slash">operator /</a> ( const path & rhs ) const;
|
||||
|
||||
// conversion functions:
|
||||
const std::string & <a href="#string">string</a>() const;
|
||||
std::string <a href="#native_file_string">native_file_string</a>() const;
|
||||
std::string <a href="#native_directory_string">native_directory_string</a>() const;
|
||||
|
||||
// decomposition functions:
|
||||
path <a href="#root_path">root_path</a>() const;
|
||||
std::string <a href="#root_name">root_name</a>() const;
|
||||
std::string <a href="#root_directory">root_directory</a>() const;
|
||||
path <a href="#relative_path">relative_path</a>() const;
|
||||
std::string <a href="#leaf">leaf</a>() const;
|
||||
path <a href="#branch_path">branch_path</a>() const;
|
||||
|
||||
// query functions:
|
||||
bool <a href="#empty">is_null()</a> const;
|
||||
const std::string & <a href="#generic_path">generic_path</a>() const;
|
||||
const std::string & <a href="#file_path">file_path</a>() const;
|
||||
const std::string & <a href="#directory_path">directory_path</a>() const;
|
||||
const std::string <a href="#leaf">leaf</a>() const;
|
||||
const path <a href="#branch">branch</a>() const;
|
||||
|
||||
bool empty() const;
|
||||
bool is_complete() const;
|
||||
bool has_root_path() const;
|
||||
bool has_root_name() const;
|
||||
bool has_root_directory() const;
|
||||
bool has_relative_path() const;
|
||||
bool has_leaf() const;
|
||||
bool has_branch_path() const;
|
||||
|
||||
// iteration:
|
||||
typedef <i>implementation-defined</i> <a href="#iterator">iterator</a>;
|
||||
const iterator <a href="#begin">begin</a>() const;
|
||||
const iterator <a href="#end">end</a>() const;
|
||||
iterator <a href="#begin">begin</a>() const;
|
||||
iterator <a href="#end">end</a>() const;
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_name; // for exposition only
|
||||
};
|
||||
|
||||
const path <a href="#non-member operator shift">operator<<</a> ( const char * lhs, const path & rhs );
|
||||
const path <a href="#non-member operator shift">operator<<</a> ( const std::string & lhs, const path & rhs );
|
||||
path <a href="#non-member_operator_shift">operator /</a> ( const char * lhs, const path & rhs );
|
||||
path <a href="#non-member_operator_shift">operator /</a> ( const std::string & lhs, const path & rhs );
|
||||
|
||||
<i>// Also see </i><a href="#Undocumented non-member functions">Undocumented non-member functions</a><i> below</i>
|
||||
|
||||
}
|
||||
}</pre>
|
||||
<p><b>Rationale:</b> The return type of several functions (<i>operator<<,
|
||||
leaf, branch</i>) is <i>const path</i> instead of <i>path</i> to disallow
|
||||
expressions like <i>(p1<<p2) = p3</i>. See Scott Myers, <i>Effective C++</i>,
|
||||
Item 21. Likewise, <i>begin()</i> and <i>end()</i> return <i>const iterator</i>
|
||||
rather than <i>iterator</i>. This detects non-portable code such as <i>++pth.begin()</i>,
|
||||
which will not work if <i>iterator</i> is a non-class type. See <i>next()</i>
|
||||
and <i>prior()</i> in <a href="../../utility/utility.htm">boost/utility.hpp</a>.</p>
|
||||
<h2><a name="Member">Member</a> functions</h2>
|
||||
<p>For the sake of exposition, class <i>path</i> member functions are described
|
||||
as if the class contains a private member <i>std::vector<std::string> m_name</i>.
|
||||
Actual implementations may differ.</p>
|
||||
<p><b>Rationale:</b> Return types of query functions have been chosen to match
|
||||
the types needed by important uses, and to be efficient in common
|
||||
implementations.</p>
|
||||
<p>Class path member, or non-member operator/, functions may throw a
|
||||
<a href="exception.htm">filesystem_error</a> exception if the path is not in the
|
||||
syntax specified for the <a href="#Grammar">grammar</a>.</p>
|
||||
<p><b>Note:</b> There is no guarantee that a <i>path</i> object represents a
|
||||
path which is considered valid by the current operating system. A path might be
|
||||
invalid to the operating system because it contains invalid names (too long,
|
||||
@ -175,15 +191,8 @@ considers too long or contains invalid characters.
|
||||
<a href="???????to-be-supplied">Validity checking functions</a> are supplied to
|
||||
ensure names in paths are as portable as desired, but they must be explicitly
|
||||
called by the user.</p>
|
||||
<p><b><a name="Naming Rationale">Naming Rationale</a>:</b> Class <i>path</i>
|
||||
member function names and <a href="operations.htm">operations.hpp</a> non-member
|
||||
function names are chosen to be distinct from one another. Otherwise, given a
|
||||
path <i>foo</i>, for example, both <i>foo.empty()</i> and <i>empty( foo )</i>
|
||||
would be valid, but with completely different semantics. Avoiding this was
|
||||
considered more important than consistency with some C++ Standard Library naming
|
||||
conventions, which aren't followed uniformly anyhow, even in the standard.</p>
|
||||
<h3><a name="System-specific Representation">System-specific Representation</a></h3>
|
||||
<p>Several <i>path</i> non-member functions return representations of <i>m_name</i>
|
||||
<h3><a name="System-specific_Representation">System-specific Representation</a></h3>
|
||||
<p>Several <i>path</i> member functions return representations of <i>m_name</i>
|
||||
in formats specific to the operating system. These formats are implementation
|
||||
defined. If an <i>m_name</i>
|
||||
element contains characters which are invalid under the operating system's
|
||||
@ -192,35 +201,68 @@ a valid character, the implementation is required to perform that translation.
|
||||
For example, if an operating system does not permit lowercase letters in file or
|
||||
directory names, these letters will be translated to uppercase if unambiguous.
|
||||
Such translation does not apply to generic path string format representations.</p>
|
||||
<h3><a name="Representation example">Representation example</a></h3>
|
||||
<p>The difference between the representations returned by <i>generic path()</i>,
|
||||
<i>directory_path()</i>, and <i>file_path()</i> are illustrated by the following
|
||||
<h3><a name="Representation_example">Representation example</a></h3>
|
||||
<p>The rule-of-thumb is to use <i>string()</i> when a generic string representation of
|
||||
the path is required, and use either
|
||||
<i>native_directory_string()</i> or
|
||||
<i>native_file_string()</i> when a string representation formatted for
|
||||
the particular operating system is required.</p>
|
||||
<p>The difference between the representations returned by <i>string()</i>,
|
||||
<i>native_directory_string()</i>, and
|
||||
<i>native_file_string()</i> are illustrated by the following
|
||||
code:</p>
|
||||
<blockquote>
|
||||
<pre>path my_path( "foo/bar/data.txt" );
|
||||
std::cout << "generic_path---: " << my_path.generic_path() << '\n'
|
||||
<< "directory_path-: " << my_path.directory_path() << '\n'
|
||||
<< "file_path------: " << my_path.file_path() << '\n';</pre>
|
||||
std::cout
|
||||
<< "string------------------: " << my_path.string() << '\n'
|
||||
<< "native_directory_string-: " << my_path.native_directory_string() << '\n'
|
||||
<< "native_file_string------: " << my_path.native_file_string() << '\n';</pre>
|
||||
</blockquote>
|
||||
<p>On POSIX or Windows, the output representations would be identical:</p>
|
||||
<p>On POSIX systems, the output would be:</p>
|
||||
<blockquote>
|
||||
<pre>generic_path---: foo/bar/data.txt
|
||||
directory_path-: foo/bar/data.txt
|
||||
file_path------: foo/bar/data.txt</pre>
|
||||
<pre>string------------------: foo/bar/data.txt
|
||||
native_directory_string-: foo/bar/data.txt
|
||||
native_file_string------: foo/bar/data.txt</pre>
|
||||
</blockquote>
|
||||
<p>But on a hypothetical operating system using OpenVMS format representations,
|
||||
they would each be different:</p>
|
||||
<p>On Windows, the output would be:</p>
|
||||
<blockquote>
|
||||
<pre>generic_path---: foo/bar/data.txt
|
||||
directory_path-: [foo.bar.data.txt]
|
||||
file_path------: [foo.bar]data.txt</pre>
|
||||
<pre>string------------------: foo/bar/data.txt
|
||||
native_directory_string-: foo\bar\data.txt
|
||||
native_file_string------: foo\bar\data.txt</pre>
|
||||
</blockquote>
|
||||
<p>Note that that because this system uses period as both a directory separator
|
||||
character and as a separator between filename and extension, <i>directory_path()</i>
|
||||
<p>On classic Mac OS, the output would be:</p>
|
||||
<blockquote>
|
||||
<pre>string------------------: foo/bar/data.txt
|
||||
native_directory_string-: foo:bar:data.txt
|
||||
native_file_string------: foo:bar:data.txt</pre>
|
||||
</blockquote>
|
||||
<p>On a hypothetical operating system using OpenVMS format representations, it would be:</p>
|
||||
<blockquote>
|
||||
<pre>string------------------: foo/bar/data.txt
|
||||
native_directory_string-: [foo.bar.data.txt]
|
||||
native_file_string------: [foo.bar]data.txt</pre>
|
||||
</blockquote>
|
||||
<p>Note that that because OpenVMS uses period as both a directory separator
|
||||
character and as a separator between filename and extension, <i>
|
||||
native_directory_string()</i>
|
||||
in the example produces a useless result. On this operating system, the
|
||||
programmer should only use this path as a file path. (There is a
|
||||
<a href="portability_guide.htm#recommendations">portability recommendation</a>
|
||||
to not use periods in directory names.)</p>
|
||||
<h3>Warning for POSIX and UNIX programmers</h3>
|
||||
<p>POSIX and other UNIX-like file systems are single-rooted, while most other
|
||||
file systems are multi-rooted. Multi-rooted file systems require a system-root
|
||||
such as a drive, device, disk, volume, or share name for a path to be resolved
|
||||
to an actual specific file or directory.
|
||||
Because of this, the <i>root()</i> and <i>root_directory()</i> functions return
|
||||
identical results on UNIX and other single-rooted file systems, but different
|
||||
results on multi-rooted file systems. Thus use of the wrong function will not be
|
||||
apparent on UNIX-like systems, but will result in non-portable code which will
|
||||
fail when used on multi-rooted systems. Thus UNIX programmers should use
|
||||
particular care to choose between <i>root()</i> and <i>root_directory()</i>. If
|
||||
undecided, use <i>root()</i>.</p>
|
||||
<p>The same warning applies to <i>has_root()</i> and <i>has_root_directory()</i>.</p>
|
||||
<h2><a name="Member">Member</a> functions</h2>
|
||||
<h3><a name="constructors">constructors</a></h3>
|
||||
<blockquote>
|
||||
<pre>path();</pre>
|
||||
@ -228,10 +270,11 @@ to not use periods in directory names.)</p>
|
||||
<pre>path( const std::string & src );
|
||||
path( const char * src );</pre>
|
||||
<p><b>Precondition:</b> <i>src</i> conforms to the <a href="#Grammar">generic
|
||||
path string grammar</a> <i>relative-path</i> syntax, and contains no embedded
|
||||
path string grammar</a> <i>relative-path</i> syntax with optional <i>
|
||||
root-directory</i> prefix, and contains no embedded
|
||||
'\0' characters.</p>
|
||||
<p><b>Effects:</b> For each <i>src</i> <i>element</i>, <code>m_name.push_back( <i>element</i> )</code>.</p>
|
||||
<p><b>Postcondition:</b> <code>m_name</code> has been reduced to
|
||||
<p><b>Postcondition:</b> <code>m_name</code> is in
|
||||
<a href="#Canonical">canonical form</a>.</p>
|
||||
<p><b>Rationale:</b> These constructors are not explicit because an intended
|
||||
use is automatic conversion of strings to paths. </p>
|
||||
@ -239,134 +282,459 @@ path( const char * src );</pre>
|
||||
path( const char * src, path_format );</pre>
|
||||
<p><b>Precondition:</b> <i>src</i> conforms to the operating system's grammar
|
||||
for path strings, and contains no embedded '\0' characters.</p>
|
||||
<p><b>Effects:</b> For each <i>src</i> element (where an element represents a
|
||||
directory name, file name, or parent-directory indicator), <code>m_name.push_back( <i>element</i> )</code>.</p>
|
||||
<p><b>Postcondition:</b> <code>m_name</code> has been reduced to
|
||||
<p><b>Effects:</b> For each <i>src</i> element, <code>m_name.push_back( <i>element</i> )</code>.</p>
|
||||
<p><b>Postcondition:</b> <code>m_name</code> is in
|
||||
<a href="#Canonical">canonical form</a>.</p>
|
||||
</blockquote>
|
||||
<h3><a name="operator-shift-equal">operator <<=</a></h3>
|
||||
<h3><a name="operator_slash_equal">operator /=</a></h3>
|
||||
<blockquote>
|
||||
<pre>path & operator<<=( const path & rhs );</pre>
|
||||
<p><b>Effects:</b> Append <code>rhs.m_name</code> to <code>m_name</code>.</p>
|
||||
<pre>path & operator/=( const path & rhs );</pre>
|
||||
<p><b>Effects:</b> If any of the following conditions are met, then
|
||||
m_name.push_back("/").</p>
|
||||
<ul>
|
||||
<li>has_relative_path().</li>
|
||||
<li>!is_absolute() && has_root_name(), and the operating system
|
||||
requires the system-specific root be absolute</li>
|
||||
</ul>
|
||||
<p> Then append <code>rhs.m_name</code> to <code>m_name</code>.</p>
|
||||
<p>(Footnote: Thus on Windows, (path("//share") /= "foo").string() is
|
||||
"//share/foo")</p>
|
||||
<p><b>Returns:</b> <code>*this</code></p>
|
||||
<p><b>Postcondition:</b> <code>m_name</code> has been reduced to
|
||||
<p><b>Postcondition:</b> <code>m_name</code> is in
|
||||
<a href="#Canonical">canonical form</a>.</p>
|
||||
<p><b>Rationale:</b> It is not considered an error for <code>rhs</code> to
|
||||
include a <code>system-specific-root</code> because it might relative, and
|
||||
include a <code>root-name</code> because it might relative, and
|
||||
thus valid. For example, on Windows, the follow must succeed:</p>
|
||||
<blockquote>
|
||||
<pre>path p( "c:", system_specific );
|
||||
p <<= path( "/foo", system_specific );
|
||||
assert( p.generic_path() == "c:/foo" );</pre>
|
||||
<pre>path p( "c:", native );
|
||||
p /= "/foo";
|
||||
assert( p.string() == "c:/foo" );</pre>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
<h3><a name="operator-shift">operator <<</a></h3>
|
||||
<h3><a name="operator_slash">operator /</a></h3>
|
||||
<blockquote>
|
||||
<pre>const path operator<< ( const path & rhs ) const;</pre>
|
||||
<p><b>Returns:</b> <code>path( *this ) <<= rhs</code></p>
|
||||
<p><b>Rationale:</b> Operator << is supplied, because it, together with operator <<=, provides a
|
||||
<pre>const path operator/ ( const path & rhs ) const;</pre>
|
||||
<p><b>Returns:</b> <code>path( *this ) /= rhs</code></p>
|
||||
<p><b>Rationale:</b> Operator / is supplied because together with operator /=,
|
||||
it provides a
|
||||
convenient way for users to supply paths with a variable number of elements.
|
||||
For example, <code>initial_directory() << "src" << test_name</code>.
|
||||
Operator+, with operator+=, were considered as alternatives, but deemed too
|
||||
easy to confuse with those operators for std::string.</p>
|
||||
<p><b>Note:</b> Also see <a href="#non-member operator shift">non-member <i>operator<<</i></a> functions.</p>
|
||||
For example, <code>initial_directory() / "src" / test_name</code>.
|
||||
Operator+ and operator+= were considered as alternatives, but deemed too
|
||||
easy to confuse with those operators for std::string. Operator<< and
|
||||
operator=<< were until during public review it was pointed out that / and /=
|
||||
matched the generic path syntax.</p>
|
||||
<p><b>Note:</b> Also see <a href="#non-member_operator_shift">non-member <i>
|
||||
operator/</i></a> functions.</p>
|
||||
</blockquote>
|
||||
<h3><a name="is_null">is_null</a></h3>
|
||||
<h3><a name="string">string</a></h3>
|
||||
<blockquote>
|
||||
<pre>bool is_null() const;</pre>
|
||||
<p><b>Returns:</b> <code>m_name.size() == 0</code></p>
|
||||
</blockquote>
|
||||
<h3><a name="generic_path">generic_path</a></h3>
|
||||
<blockquote>
|
||||
<pre>const std::string & generic_path() const;</pre>
|
||||
<pre>const std::string & string() const;</pre>
|
||||
<p><b>Returns:</b> The contents of <code>m_name</code>, formatted according to
|
||||
the rules of the <a href="#Grammar">generic path string grammar</a>.</p>
|
||||
<p><b>Note:</b> If any m_name elements originated from the system specific
|
||||
constructors, there is no guarantee that the returned string is unambiguous
|
||||
according to the grammar. A system-specific-root indistinguishable from a
|
||||
according to the grammar. A root-name indistinguishable from a
|
||||
relative-path name, a name containing "/", a name "..", and a
|
||||
system-specific-root beyond the first element all could cause ambiguities. Such
|
||||
root-name beyond the first element all could cause ambiguities. Such
|
||||
an ambiguous representation might still be useful for some purposes, such as
|
||||
display. If no m_name elements originated from the system specific constructors,
|
||||
the returned string is always unambiguous.</p>
|
||||
<p><b>See:</b> <a href="#Representation example">Representation example</a>
|
||||
above.</p>
|
||||
</blockquote>
|
||||
<h3><a name="file_path">file_path</a></h3>
|
||||
<h3><a name="native_file_string">native_file_string</a></h3>
|
||||
<blockquote>
|
||||
<pre>const std::string & file_path() const;</pre>
|
||||
<pre>std::string native_file_string() const;</pre>
|
||||
<p><b>Returns:</b> The contents of <code>m_name</code>, formatted in the
|
||||
<a href="#System-specific Representation">system-specific representation</a> of
|
||||
a file path.</p>
|
||||
<p><b>See:</b> <a href="#Representation example">Representation example</a>
|
||||
above.</p>
|
||||
<p><b>Warning:</b> This function is intended only for use in calls to operating
|
||||
system or third-party libraries. Use in other contexts is probably a programming
|
||||
error. The preferred way to obtain a std::string from a path is <i>generic_path()</i>.</p>
|
||||
<p><b>Naming rationale</b>: The name is deliberately ugly to warn users that
|
||||
this function yields non-portable results.</p>
|
||||
</blockquote>
|
||||
<h3><a name="directory_path">directory_path</a></h3>
|
||||
<h3><a name="native_directory_string">native_directory_string</a></h3>
|
||||
<blockquote>
|
||||
<pre>const std::string & directory_path() const;</pre>
|
||||
<pre>const std::string native_file_string() const;</pre>
|
||||
<p><b>Returns:</b> The contents of <code>m_name</code>, formatted in the
|
||||
<a href="#System-specific Representation">system-specific representation</a> of
|
||||
a directory path.</p>
|
||||
<p><b>See:</b> <a href="#Representation example">Representation example</a>
|
||||
above.</p>
|
||||
<p><b>Warning:</b> This function is intended only for use in calls to operating
|
||||
system or third-party libraries. Use in other contexts is probably a programming
|
||||
error. The preferred way to obtain a std::string from a path is <i>generic_path()</i>.</p>
|
||||
<p><b>Naming rationale</b>: The name is deliberately ugly to warn users that
|
||||
this function yields non-portable results.</p>
|
||||
</blockquote>
|
||||
<h3><a name="root_path">root_path</a></h3>
|
||||
<blockquote>
|
||||
<pre>path root_path() const;</pre>
|
||||
<p><b>Returns:</b> <code>root_name() / root_directory()</code></p>
|
||||
<p>Portably provides a copy of a path's full root path, if any. See
|
||||
<a href="#decomposition">Path decomposition examples</a>.</p>
|
||||
</blockquote>
|
||||
<h3><a name="root_name">root_name</a></h3>
|
||||
<blockquote>
|
||||
<pre>std::string root_name() const;</pre>
|
||||
<p><b>Returns:</b> If <code>!m_name.empty() && m_name[0]</code> is a
|
||||
<a href="#Grammar">root-name</a>, returns m_name[0], else returns a
|
||||
null string.</p>
|
||||
<p>Portably provides a copy of a path's <a href="#Grammar">root-name</a>,
|
||||
if any. See <a href="#decomposition">Path decomposition examples</a>.</p>
|
||||
</blockquote>
|
||||
<h3><a name="root_directory">root_directory</a></h3>
|
||||
<blockquote>
|
||||
<pre>std::string root_directory() const;</pre>
|
||||
<p><b>Returns:</b> If the path contains <a href="#Grammar">root-directory</a>,
|
||||
then <code>string("")</code>, else <code>string()</code>.</p>
|
||||
<p>Portably provides a copy of a path's <a href="#Grammar">root-directory</a>,
|
||||
if any. The only possible results are "/" or "". See <a href="#decomposition">
|
||||
Path decomposition examples</a>.</p>
|
||||
</blockquote>
|
||||
<h3><a name="relative_path">relative_path</a></h3>
|
||||
<blockquote>
|
||||
<pre>path relative_path() const;</pre>
|
||||
<p><b>Returns:</b> A new path containing only the <a href="#Grammar">
|
||||
relative-path</a> portion of the source path.</p>
|
||||
<p>Portably provides a copy of a path's relative portion, if any. See
|
||||
<a href="#decomposition">Path decomposition examples</a>.</p>
|
||||
</blockquote>
|
||||
<h3><a name="leaf">leaf</a></h3>
|
||||
<blockquote>
|
||||
<pre>const std::string leaf() const;</pre>
|
||||
<pre>std::string leaf() const;</pre>
|
||||
<p><b>Returns:</b> <code>is_null() ? std::string() : m_name.back()</code></p>
|
||||
<p><b>Rationale: </b>Return type is <code>const string</code> rather than <code>const
|
||||
string &</code> to give implementations freedom to avoid maintaining the
|
||||
leaf as a separate <code>string</code> object.</p>
|
||||
<p>A typical use is to obtain the undecorated name of a directory entry from the
|
||||
path returned by a <a href="operations.htm#directory_iterator">
|
||||
directory_iterator</a>. See <a href="#decomposition">Path decomposition examples</a>.</p>
|
||||
</blockquote>
|
||||
<h3><a name="branch">branch</a></h3>
|
||||
<h3><a name="branch_path">branch_path</a></h3>
|
||||
<blockquote>
|
||||
<pre>const path branch() const;</pre>
|
||||
<pre>path branch_path() const;</pre>
|
||||
<p><b>Returns:</b> <code>m_name.size() <= 1 ? path("") : x</code>, where <code>x</code>
|
||||
is a path constructed from all the elements of <code>m_name</code> except the
|
||||
last.</p>
|
||||
<p>A typical use is to obtain the parent path for a path supplied by the user.
|
||||
See <a href="#decomposition">Path decomposition examples</a>.</p>
|
||||
</blockquote>
|
||||
<h3><a name="empty">empty</a></h3>
|
||||
<blockquote>
|
||||
<pre>bool empty() const;</pre>
|
||||
<p><b>Returns:</b> <code>m_name.empty()</code>.</p>
|
||||
<p><b>Naming rationale:</b> Because the equivalent function for standard
|
||||
library container is named empty(), prior versions with other names caused
|
||||
numerous typos. The problem was acerbated because tests for path emptyness are
|
||||
often used near, or in the same expression, with tests for string emptyness,
|
||||
</p>
|
||||
</blockquote>
|
||||
<h3>is_complete</h3>
|
||||
<blockquote>
|
||||
<pre>bool is_complete() const;</pre>
|
||||
<p><b>Returns:</b> For single-rooted file systems, <code>has_root_directory()</code>.
|
||||
For multi-rooted file systems, <code>has_root_directory() &&
|
||||
has_root_name()</code>.</p>
|
||||
<p><b>Naming rationale:</b> The alternate name, is_absolute(), causes
|
||||
confusion and controversy because on multi-rooted file systems some people
|
||||
believe root_name() should participate in is_absolute(), and some
|
||||
don't.</p>
|
||||
</blockquote>
|
||||
<h3>has_root_path</h3>
|
||||
<blockquote>
|
||||
<pre>bool has_root_path() const;</pre>
|
||||
<p><b>Returns:</b> <code>has_root_name() || has_root_directory()</code></p>
|
||||
</blockquote>
|
||||
<h3>has_root_name</h3>
|
||||
<blockquote>
|
||||
<pre>bool has_root_name() const;</pre>
|
||||
<p><b>Returns:</b> <code>!root_name().empty()</code></p>
|
||||
</blockquote>
|
||||
<h3>has_root_directory</h3>
|
||||
<blockquote>
|
||||
<pre>bool has_root_directory() const;</pre>
|
||||
<p><b>Returns:</b> <code>!root_directory().empty()</code></p>
|
||||
</blockquote>
|
||||
<h3>has_relative_path</h3>
|
||||
<blockquote>
|
||||
<pre>bool has_relative_path() const;</pre>
|
||||
<p><b>Returns:</b> <code>!relative_path().empty()</code></p>
|
||||
</blockquote>
|
||||
<h3>has_leaf</h3>
|
||||
<blockquote>
|
||||
<pre>bool has_leaf() const;</pre>
|
||||
<p><b>Returns:</b> <code>!leaf().empty()</code></p>
|
||||
</blockquote>
|
||||
<h3>has_branch_path</h3>
|
||||
<blockquote>
|
||||
<pre>bool has_branch_path() const;</pre>
|
||||
<p><b>Returns:</b> <code>!branch_path().empty()</code></p>
|
||||
</blockquote>
|
||||
<h3><a name="iterator">iterator</a></h3>
|
||||
<blockquote>
|
||||
<p><code>typedef <i>implementation-defined</i> iterator;</code></p>
|
||||
<p>An iterator meeting the C++ Standard Library requirements for bidirectional
|
||||
iterators (24.1). The value, reference, and pointer types are <i>std::string</i>,
|
||||
<p>A const iterator meeting the C++ Standard Library requirements for bidirectional
|
||||
iterators (24.1). The iterator is a class type (so that operator++ and -- will
|
||||
work on temporaries). The value, reference, and pointer types are <i>std::string</i>,
|
||||
<i>const std::string &</i>, and <i>const std::string *</i>, respectively.</p>
|
||||
</blockquote>
|
||||
<h3><a name="begin">begin</a></h3>
|
||||
<blockquote>
|
||||
<p><code>const iterator begin() const;</code></p>
|
||||
<p><code>iterator begin() const;</code></p>
|
||||
<p><b>Returns:</b> <code>m_path.begin()</code></p>
|
||||
</blockquote>
|
||||
<h3><a name="end">end</a></h3>
|
||||
<blockquote>
|
||||
<p><code>const iterator end() const;</code></p>
|
||||
<p><code>iterator end() const;</code></p>
|
||||
<p><b>Returns:</b> <code>m_path.end()</code></p>
|
||||
</blockquote>
|
||||
<h2><a name="Non-member functions">Non-member functions</a></h2>
|
||||
<h3><a name="non-member operator shift">Non-member operator<<</a></h3>
|
||||
<h2><a name="Non-member_functions">Non-member functions</a></h2>
|
||||
<h3><a name="non-member_operator_shift">Non-member operator /</a></h3>
|
||||
<blockquote>
|
||||
<p><code>const path operator << ( const char * lhs, const path & rhs );<br>
|
||||
const
|
||||
path operator << ( const std::string & lhs, const path & rhs );</code></p>
|
||||
<p><b>Returns:</b> <code>path( lhs ) <<= rhs</code></p>
|
||||
<p><code>path operator / ( const char * lhs, const path & rhs );<br>
|
||||
path operator / ( const std::string & lhs, const path & rhs );</code></p>
|
||||
<p><b>Returns:</b> <code>path( lhs ) /= rhs</code></p>
|
||||
</blockquote>
|
||||
<h3><a name="Undocumented non-member functions">Undocumented non-member
|
||||
functions</a></h3>
|
||||
<h2><a name="Validity_checking">Validity checking functions</a></h2>
|
||||
<h3>Undocumented non-member
|
||||
functions</h3>
|
||||
<p>The header <a href="../../../boost/filesystem/path.hpp">boost/filesystem/path.hpp</a>
|
||||
also supplies several non-member functions which can be used to verify that a
|
||||
path meets certain requirements. These subsidiary functions are undocumented
|
||||
pending more research and discussion, and should not be relied upon as they are
|
||||
likely to change.</p>
|
||||
<h2><a name="Rationale">Rationale</a></h2>
|
||||
<p><b>Function <a name="Naming_Rationale">naming</a>:</b> Class <i>path</i>
|
||||
member function names and <a href="operations.htm">operations.hpp</a> non-member
|
||||
function names were chosen to be somewhat distinct from one another. The
|
||||
objective was to avoid cases like <i>foo.empty()</i> and <i>empty( foo )</i> both being
|
||||
valid, but with completely different semantics. At one point <i>path::empty()</i>
|
||||
was renamed <i>path::is_null()</i>, but that caused many coding typos because <i>
|
||||
std::string::empty()</i> is often used nearby.</p>
|
||||
<p><b>Decomposition functions:</b> Decomposition functions are provided because without them it is impossible to write portable path
|
||||
manipulations. Convenience is also a factor.</p>
|
||||
<p><b>Const vs non-const returns:</b> In some earlier versions of the library,
|
||||
member functions returned values as const rather than non-const.
|
||||
See Scott Myers, <i>Effective C++</i>, Item 21. The const qualifiers were
|
||||
eliminated (1) to conform with C++ Standard Library practice, (2) because
|
||||
non-const returns allow occasionally useful expressions, and (3) because the
|
||||
number of coding errors eliminated were deemed rare. A requirement that path::iterator not be a non-class type was added to eliminate errors non-const
|
||||
iterator errors.</p>
|
||||
<h2>Path <a name="decomposition">decomposition</a> examples</h2>
|
||||
<p>It is often useful to extract specific elements from a path object.
|
||||
While any decomposition can be achieved by iterating over the elements of a
|
||||
path, convenience functions are provided which are easier to use, more
|
||||
efficient, and less error prone.</p>
|
||||
<p>The first column of the table gives the example path, formatted by the
|
||||
string() function. The second column shows the values which would be returned by
|
||||
dereferencing each element iterator. The remaining columns show the results of
|
||||
various expressions.</p>
|
||||
<table border="1" cellpadding="5" cellspacing="0">
|
||||
<tr>
|
||||
<td><b>p.string()</b></td>
|
||||
<td><b>Elements</b></td>
|
||||
<td><b>p.root_<br>
|
||||
path()<br>
|
||||
</b></td>
|
||||
<td><b>p.root_<br>
|
||||
name()</b></td>
|
||||
<td><b>p.root_<br>
|
||||
directory()</b></td>
|
||||
<td><b>p.relative_<br>
|
||||
path()</b></td>
|
||||
<td><b>p.root_<br>
|
||||
directory()<br>
|
||||
/ p.relative_<br>
|
||||
path()</b></td>
|
||||
<td><b>p.root_<br>
|
||||
name() /<br>
|
||||
p.relative_<br>
|
||||
path()</b></td>
|
||||
<td><b>p.branch_<br>
|
||||
path()</b></td>
|
||||
<td><b>p.leaf()</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>All systems</b></td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/</code></td>
|
||||
<td><code>/</code></td>
|
||||
<td><code>/</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>/</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>/</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>/</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>foo</code></td>
|
||||
<td><code>foo</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>foo</code></td>
|
||||
<td><code>foo</code></td>
|
||||
<td><code>foo</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>foo</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/foo</code></td>
|
||||
<td><code>/,foo</code></td>
|
||||
<td><code>/</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>/</code></td>
|
||||
<td><code>foo</code></td>
|
||||
<td><code>/foo</code></td>
|
||||
<td><code>foo</code></td>
|
||||
<td><code>/</code></td>
|
||||
<td><code>foo</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>foo/bar</code></td>
|
||||
<td><code>foo,bar</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>foo/bar</code></td>
|
||||
<td><code>foo/bar</code></td>
|
||||
<td><code>foo/bar</code></td>
|
||||
<td><code>foo</code></td>
|
||||
<td><code>bar</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>/foo/bar</code></td>
|
||||
<td><code>/,foo,bar</code></td>
|
||||
<td><code>/</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>/</code></td>
|
||||
<td><code>foo/bar</code></td>
|
||||
<td><code>/foo/bar</code></td>
|
||||
<td><code>foo/bar</code></td>
|
||||
<td><code>/foo</code></td>
|
||||
<td><code>bar</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Windows</b></td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>c:</code></td>
|
||||
<td><code>c:</code></td>
|
||||
<td><code>c:</code></td>
|
||||
<td><code>c:</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>c:</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>c:</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>c:foo</code></td>
|
||||
<td><code>c:,foo</code></td>
|
||||
<td><code>c:</code></td>
|
||||
<td><code>c:</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>foo</code></td>
|
||||
<td><code>foo</code></td>
|
||||
<td><code>c:foo</code></td>
|
||||
<td><code>c:</code></td>
|
||||
<td><code>foo</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>c:/</code></td>
|
||||
<td><code>c:,/</code></td>
|
||||
<td><code>c:/</code></td>
|
||||
<td><code>c:</code></td>
|
||||
<td><code>/</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>/</code></td>
|
||||
<td><code>c:</code></td>
|
||||
<td><code>c:</code></td>
|
||||
<td><code>/</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>c:/foo</code></td>
|
||||
<td><code>c:,/,foo</code></td>
|
||||
<td><code>c:/</code></td>
|
||||
<td><code>c:</code></td>
|
||||
<td><code>/</code></td>
|
||||
<td><code>foo</code></td>
|
||||
<td><code>/foo</code></td>
|
||||
<td><code>c:foo</code></td>
|
||||
<td><code>c:/</code></td>
|
||||
<td><code>foo</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>//shr</code></td>
|
||||
<td><code>//shr</code></td>
|
||||
<td><code>//shr</code></td>
|
||||
<td><code>//shr</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>//shr</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>//shr</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>//shr/</code></td>
|
||||
<td><code>//shr,/</code></td>
|
||||
<td><code>//shr/</code></td>
|
||||
<td><code>//shr</code></td>
|
||||
<td><code>/</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>/</code></td>
|
||||
<td><code>//shr</code></td>
|
||||
<td><code>//shr</code></td>
|
||||
<td><code>/</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>//shr/foo</code></td>
|
||||
<td><code>//shr,<br>
|
||||
/,foo</code></td>
|
||||
<td><code>//shr/</code></td>
|
||||
<td><code>//shr</code></td>
|
||||
<td><code>/</code></td>
|
||||
<td><code>foo</code></td>
|
||||
<td><code>/foo</code></td>
|
||||
<td><code>//shr/foo</code></td>
|
||||
<td><code>//shr/</code></td>
|
||||
<td><code>foo</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>prn:</code></td>
|
||||
<td><code>prn:</code></td>
|
||||
<td><code>prn:</code></td>
|
||||
<td><code>prn:</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>prn:</code></td>
|
||||
<td><code>""</code></td>
|
||||
<td><code>prn:</code></td>
|
||||
</tr>
|
||||
</table>
|
||||
<hr>
|
||||
<p>© Copyright Beman Dawes, 2002</p>
|
||||
<p>Revised
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->20 September, 2002<!--webbot bot="Timestamp" endspan i-checksum="39331" --></p>
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->11 December, 2002<!--webbot bot="Timestamp" endspan i-checksum="38505" --></p>
|
||||
|
||||
</body>
|
||||
|
||||
|
74
example/simple_ls.cpp
Normal file
74
example/simple_ls.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
// simple_ls program -------------------------------------------------------//
|
||||
|
||||
// (C) Copyright Jeff Garland and Beman Dawes, 2002. Permission to copy, use,
|
||||
// modify, sell and distribute this software is granted provided this copyright
|
||||
// notice appears in all copies. This software is provided "as is" without
|
||||
// express or implied warranty, and with no claim as to its suitability for
|
||||
// any purpose.
|
||||
|
||||
// See http://www.boost.org/libs/filesystem for documentation.
|
||||
|
||||
#include "boost/filesystem/operations.hpp"
|
||||
#include "boost/filesystem/path.hpp"
|
||||
#include <iostream>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
int main( int argc, char* argv[] )
|
||||
{
|
||||
|
||||
fs::path full_path( fs::initial_path() );
|
||||
|
||||
if ( argc > 1 )
|
||||
full_path = fs::system_complete( fs::path( argv[1], fs::native ) );
|
||||
else
|
||||
std::cout << "\nusage: simple_ls [path]" << std::endl;
|
||||
|
||||
unsigned long file_count = 0;
|
||||
unsigned long dir_count = 0;
|
||||
unsigned long err_count = 0;
|
||||
|
||||
if ( !fs::exists( full_path ) )
|
||||
{
|
||||
std::cout << "\nNot found: " << full_path.native_file_string() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( fs::is_directory( full_path ) )
|
||||
{
|
||||
std::cout << "\nIn directory: "
|
||||
<< full_path.native_directory_string() << "\n\n";
|
||||
fs::directory_iterator end_iter;
|
||||
for ( fs::directory_iterator dir_itr( full_path );
|
||||
dir_itr != end_iter;
|
||||
++dir_itr )
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( fs::is_directory( *dir_itr ) )
|
||||
{
|
||||
++dir_count;
|
||||
std::cout << dir_itr->leaf()<< " [directory]\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
++file_count;
|
||||
std::cout << dir_itr->leaf() << "\n";
|
||||
}
|
||||
}
|
||||
catch ( const std::exception & ex )
|
||||
{
|
||||
++err_count;
|
||||
std::cout << dir_itr->leaf() << " " << ex.what();
|
||||
}
|
||||
}
|
||||
std::cout << "\n" << file_count << " files\n"
|
||||
<< dir_count << " directories\n"
|
||||
<< err_count << " errors\n";
|
||||
}
|
||||
else // must be a file
|
||||
{
|
||||
std::cout << "\nFound: " << full_path.native_file_string() << "\n";
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -14,7 +14,7 @@
|
||||
|
||||
// Original author: Dietmar Kühl. Revised by Beman Dawes.
|
||||
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
// See http://www.boost.org/libs/filesystem for documentation.
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
@ -22,7 +22,6 @@
|
||||
#include <boost/filesystem/exception.hpp>
|
||||
|
||||
#include <cstring> // SGI MIPSpro compilers need this
|
||||
#include <cerrno>
|
||||
#include <string>
|
||||
|
||||
# ifdef BOOST_NO_STDC_NAMESPACE
|
||||
@ -42,6 +41,8 @@
|
||||
|
||||
# if defined( BOOST_WINDOWS )
|
||||
# include "windows.h"
|
||||
# else
|
||||
# include <errno.h> // for POSIX error codes
|
||||
# endif
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
@ -50,56 +51,119 @@ namespace boost
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
|
||||
filesystem_error::filesystem_error( std::string const& msg ):
|
||||
std::runtime_error("filesystem error"),
|
||||
m_msg(msg),
|
||||
m_err(0)
|
||||
namespace detail
|
||||
{
|
||||
std::string prep_msg( const std::string & msg, error_code ec )
|
||||
{
|
||||
std::string str( "File system error: " );
|
||||
str += msg;
|
||||
if ( ec == system_error )
|
||||
{
|
||||
str += ": ";
|
||||
# ifdef BOOST_WINDOWS
|
||||
LPVOID lpMsgBuf;
|
||||
::FormatMessageA(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
::GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
||||
(LPSTR) &lpMsgBuf,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
str += static_cast<LPCSTR>(lpMsgBuf);
|
||||
::LocalFree( lpMsgBuf ); // free the buffer
|
||||
# else
|
||||
str += std::strerror( errno );
|
||||
# endif
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
struct ec_xlate { int sys_ec; error_code ec; };
|
||||
const ec_xlate ec_table[] =
|
||||
{
|
||||
# ifdef BOOST_WINDOWS
|
||||
{ ERROR_ACCESS_DENIED, security_error },
|
||||
{ ERROR_INVALID_ACCESS, security_error },
|
||||
{ ERROR_SHARING_VIOLATION, security_error },
|
||||
{ ERROR_LOCK_VIOLATION, security_error },
|
||||
{ ERROR_LOCKED, security_error },
|
||||
{ ERROR_NOACCESS, security_error },
|
||||
{ ERROR_WRITE_PROTECT, read_only_error },
|
||||
{ ERROR_NOT_READY, io_error },
|
||||
{ ERROR_SEEK, io_error },
|
||||
{ ERROR_READ_FAULT, io_error },
|
||||
{ ERROR_WRITE_FAULT, io_error },
|
||||
{ ERROR_CANTOPEN, io_error },
|
||||
{ ERROR_CANTREAD, io_error },
|
||||
{ ERROR_CANTWRITE, io_error },
|
||||
{ ERROR_DIRECTORY, path_error },
|
||||
{ ERROR_INVALID_NAME, path_error },
|
||||
{ ERROR_FILE_NOT_FOUND, not_found_error },
|
||||
{ ERROR_PATH_NOT_FOUND, not_found_error },
|
||||
{ ERROR_DEV_NOT_EXIST, not_found_error },
|
||||
{ ERROR_DEVICE_IN_USE, busy_error },
|
||||
{ ERROR_OPEN_FILES, busy_error },
|
||||
{ ERROR_BUSY_DRIVE, busy_error },
|
||||
{ ERROR_BUSY, busy_error },
|
||||
{ ERROR_FILE_EXISTS, already_exists_error },
|
||||
{ ERROR_ALREADY_EXISTS, already_exists_error },
|
||||
{ ERROR_DIR_NOT_EMPTY, not_empty_error },
|
||||
{ ERROR_HANDLE_DISK_FULL, out_of_space_error },
|
||||
{ ERROR_DISK_FULL, out_of_space_error },
|
||||
{ ERROR_OUTOFMEMORY, out_of_memory_error },
|
||||
{ ERROR_NOT_ENOUGH_MEMORY, out_of_memory_error },
|
||||
{ ERROR_TOO_MANY_OPEN_FILES, out_of_resource_error }
|
||||
# else
|
||||
{ EACCES, security_error },
|
||||
{ EROFS, read_only_error },
|
||||
{ EIO, io_error },
|
||||
{ ENAMETOOLONG, path_error },
|
||||
{ ENOENT, not_found_error },
|
||||
{ ENOTDIR, not_directory_error },
|
||||
{ EAGAIN, busy_error },
|
||||
{ EBUSY, busy_error },
|
||||
{ ETXTBSY, busy_error },
|
||||
{ EEXIST, already_exists_error },
|
||||
{ ENOTEMPTY, not_empty_error },
|
||||
{ EISDIR, is_directory_error },
|
||||
{ ENOSPC, out_of_space_error },
|
||||
{ ENOMEM, out_of_memory_error },
|
||||
{ EMFILE, out_of_resource_error }
|
||||
# endif
|
||||
};
|
||||
}
|
||||
|
||||
filesystem_error::filesystem_error( std::string const& msg, error_type ):
|
||||
std::runtime_error("filesystem error"),
|
||||
m_msg(msg),
|
||||
# ifdef BOOST_WINDOWS
|
||||
m_err( ::GetLastError() )
|
||||
# else
|
||||
m_err(errno) // GCC 3.1 won't accept ::errno
|
||||
# endif
|
||||
filesystem_error::filesystem_error( std::string const& msg, error_code ec )
|
||||
: std::runtime_error( detail::prep_msg( msg, ec ).c_str() ),
|
||||
m_sys_err(0), m_err(ec)
|
||||
{
|
||||
if ( ec == system_error )
|
||||
{
|
||||
# ifdef BOOST_WINDOWS
|
||||
m_sys_err = ::GetLastError();
|
||||
# else
|
||||
m_sys_err = errno; // GCC 3.1 won't accept ::errno
|
||||
# endif
|
||||
|
||||
const detail::ec_xlate * cur = &detail::ec_table[0];
|
||||
for ( ; cur != detail::ec_table
|
||||
+ sizeof(detail::ec_table)/sizeof(detail::ec_xlate)
|
||||
&& m_sys_err != cur->sys_ec;
|
||||
++cur ) {}
|
||||
if ( cur != detail::ec_table
|
||||
+ sizeof(detail::ec_table)/sizeof(detail::ec_xlate) )
|
||||
{ m_err = cur->ec; }
|
||||
}
|
||||
}
|
||||
|
||||
filesystem_error::~filesystem_error() throw()
|
||||
{
|
||||
}
|
||||
|
||||
char const* filesystem_error::what() const throw()
|
||||
{
|
||||
if (m_err)
|
||||
{
|
||||
m_msg += ": ";
|
||||
# ifdef BOOST_WINDOWS
|
||||
LPVOID lpMsgBuf;
|
||||
::FormatMessageA(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
m_err,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
||||
(LPSTR) &lpMsgBuf,
|
||||
0,
|
||||
NULL
|
||||
);
|
||||
m_msg += static_cast<LPCSTR>(lpMsgBuf);
|
||||
LocalFree( lpMsgBuf ); // free the buffer
|
||||
# else
|
||||
m_msg += std::strerror(m_err);
|
||||
# endif
|
||||
m_err = 0;
|
||||
}
|
||||
return m_msg.c_str();
|
||||
}
|
||||
} // namespace filesystem
|
||||
} // namespace boost
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
// < "as is" without expressed or implied warranty. >
|
||||
// < ----------------------------------------------------------------------- >
|
||||
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
// See http://www.boost.org/libs/filesystem for documentation.
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
@ -27,6 +27,8 @@
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/filesystem/exception.hpp>
|
||||
#include <boost/scoped_array.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
//#include <iostream>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
@ -35,7 +37,14 @@ namespace fs = boost::filesystem;
|
||||
// operating system. GCC defaults to BOOST_POSIX; it doesn't predefine _WIN32.
|
||||
|
||||
# if defined(BOOST_WINDOWS) || (!defined(BOOST_POSIX) && defined(_WIN32))
|
||||
# define BOOST_WINDOWS
|
||||
# include "windows.h"
|
||||
|
||||
// For Windows, the xxxA form of various function names is used to avoid
|
||||
// inadvertently getting wide forms of the functions. (The undecorated
|
||||
// forms are actually macros, so can misfire if the user has various
|
||||
// other macros defined. There was a bug report of this happening.)
|
||||
|
||||
# else
|
||||
# define BOOST_POSIX
|
||||
# include "sys/stat.h"
|
||||
@ -89,7 +98,8 @@ namespace
|
||||
{
|
||||
if ( errno != 0 )
|
||||
{
|
||||
throw fs::filesystem_error( "directory_iterator ++() failure" );
|
||||
boost::throw_exception(
|
||||
fs::filesystem_error( "directory_iterator ++() failure", fs::other_error ) );
|
||||
}
|
||||
else { return 0; } // end reached
|
||||
}
|
||||
@ -99,19 +109,21 @@ namespace
|
||||
|
||||
# define BOOST_HANDLE HANDLE
|
||||
# define BOOST_INVALID_HANDLE_VALUE INVALID_HANDLE_VALUE
|
||||
# define BOOST_SYSTEM_DIRECTORY_TYPE WIN32_FIND_DATA
|
||||
# define BOOST_SYSTEM_DIRECTORY_TYPE WIN32_FIND_DATAA
|
||||
|
||||
inline const char * find_first_file( const char * dir,
|
||||
BOOST_HANDLE & handle, BOOST_SYSTEM_DIRECTORY_TYPE & data )
|
||||
// Returns: 0 if error, otherwise name
|
||||
{
|
||||
// std::cout << "find_first_file " << dir << std::endl;
|
||||
std::string dirpath( std::string(dir) + "/*" );
|
||||
return ( (handle = ::FindFirstFile( dirpath.c_str(), &data ))
|
||||
return ( (handle = ::FindFirstFileA( dirpath.c_str(), &data ))
|
||||
== BOOST_INVALID_HANDLE_VALUE ) ? 0 : data.cFileName;
|
||||
}
|
||||
|
||||
inline void find_close( BOOST_HANDLE handle )
|
||||
{
|
||||
// std::cout << "find_close" << std::endl;
|
||||
assert( handle != BOOST_INVALID_HANDLE_VALUE );
|
||||
::FindClose( handle );
|
||||
}
|
||||
@ -121,12 +133,12 @@ namespace
|
||||
// Returns: 0 if EOF, otherwise name
|
||||
// Throws: if system reports error
|
||||
{
|
||||
if ( ::FindNextFile( handle, &data ) == 0 )
|
||||
if ( ::FindNextFileA( handle, &data ) == 0 )
|
||||
{
|
||||
if ( ::GetLastError() != ERROR_NO_MORE_FILES )
|
||||
{
|
||||
throw fs::filesystem_error(
|
||||
"directory_iterator ++() failure", fs::system_error );
|
||||
boost::throw_exception( fs::filesystem_error(
|
||||
"directory_iterator ++() failure", fs::system_error ) );
|
||||
}
|
||||
else { return 0; } // end reached
|
||||
}
|
||||
@ -147,7 +159,7 @@ namespace
|
||||
unsigned long count = 1;
|
||||
if ( fs::is_directory( ph ) )
|
||||
{
|
||||
for ( boost::filesystem::directory_iterator itr( ph );
|
||||
for ( fs::directory_iterator itr( ph );
|
||||
itr != end_itr; ++itr )
|
||||
{
|
||||
count += remove_all_aux( *itr );
|
||||
@ -167,26 +179,28 @@ namespace boost
|
||||
{
|
||||
#ifdef BOOST_POSIX
|
||||
const char * implementation_name() { return "POSIX"; }
|
||||
bool single_root_name() { return true; }
|
||||
#else
|
||||
const char * implementation_name() { return "Windows"; }
|
||||
bool single_root_name() { return false; }
|
||||
#endif
|
||||
|
||||
// directory_iterator_imp --------------------------------------------------//
|
||||
|
||||
class directory_iterator_imp
|
||||
{
|
||||
public:
|
||||
path entry_path;
|
||||
BOOST_HANDLE handle;
|
||||
|
||||
~directory_iterator_imp()
|
||||
{
|
||||
if ( handle != BOOST_INVALID_HANDLE_VALUE ) find_close( handle );
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// dir_itr_imp -------------------------------------------------------------//
|
||||
|
||||
class directory_iterator::dir_itr_imp
|
||||
{
|
||||
public:
|
||||
path entry_path;
|
||||
BOOST_HANDLE handle;
|
||||
|
||||
~dir_itr_imp()
|
||||
{
|
||||
if ( handle != BOOST_INVALID_HANDLE_VALUE ) find_close( handle );
|
||||
}
|
||||
};
|
||||
|
||||
// directory_iterator implementation ---------------------------------------//
|
||||
|
||||
// default ctor creates the "end" iterator (by letting base default to 0)
|
||||
@ -194,54 +208,52 @@ namespace boost
|
||||
|
||||
directory_iterator::directory_iterator( const path & dir_path )
|
||||
{
|
||||
base().imp.reset( new detail::directory_iterator_imp );
|
||||
m_imp.reset( new dir_itr_imp );
|
||||
BOOST_SYSTEM_DIRECTORY_TYPE scratch;
|
||||
const char * name;
|
||||
if ( dir_path.is_null() )
|
||||
base().imp->handle = BOOST_INVALID_HANDLE_VALUE;
|
||||
if ( dir_path.empty() )
|
||||
m_imp->handle = BOOST_INVALID_HANDLE_VALUE;
|
||||
else
|
||||
name = find_first_file( dir_path.directory_path().c_str(),
|
||||
base().imp->handle, scratch ); // sets handle
|
||||
name = find_first_file( dir_path.native_directory_string().c_str(),
|
||||
m_imp->handle, scratch ); // sets handle
|
||||
|
||||
if ( base().imp->handle != BOOST_INVALID_HANDLE_VALUE )
|
||||
if ( m_imp->handle != BOOST_INVALID_HANDLE_VALUE )
|
||||
{
|
||||
base().imp->entry_path = dir_path;
|
||||
base().imp->entry_path.m_path_append( name, path::nocheck );
|
||||
while ( base().imp.get()
|
||||
&& ( base().imp->entry_path.leaf() == "."
|
||||
|| base().imp->entry_path.leaf() == ".." ) )
|
||||
m_imp->entry_path = dir_path;
|
||||
m_imp->entry_path.m_path_append( name, path::nocheck );
|
||||
while ( m_imp.get()
|
||||
&& ( m_imp->entry_path.leaf() == "."
|
||||
|| m_imp->entry_path.leaf() == ".." ) )
|
||||
{ operator++(); }
|
||||
}
|
||||
else
|
||||
{
|
||||
throw filesystem_error( std::string(
|
||||
boost::throw_exception( filesystem_error( std::string(
|
||||
"directory_iterator constructor failure: " )
|
||||
+ dir_path.directory_path().c_str(), system_error );
|
||||
+ dir_path.native_directory_string(), system_error ) );
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail
|
||||
path const & directory_iterator::m_deref() const
|
||||
{
|
||||
path const & directory_iterator_internals::deref() const
|
||||
assert( m_imp.get() ); // fails if dereference end iterator
|
||||
return m_imp->entry_path;
|
||||
}
|
||||
|
||||
void directory_iterator::m_inc()
|
||||
{
|
||||
assert( m_imp.get() ); // fails on increment end iterator
|
||||
assert( m_imp->handle != BOOST_INVALID_HANDLE_VALUE ); // reality check
|
||||
|
||||
BOOST_SYSTEM_DIRECTORY_TYPE scratch;
|
||||
const char * name;
|
||||
if ( (name = find_next_file( m_imp->handle, scratch )) != 0 )
|
||||
{
|
||||
assert( imp.get() ); // fails if dereference end iterator
|
||||
return imp->entry_path;
|
||||
m_imp->entry_path.m_replace_leaf( name );
|
||||
}
|
||||
|
||||
void directory_iterator_internals::inc()
|
||||
else
|
||||
{
|
||||
assert( imp.get() ); // fails on increment end iterator
|
||||
assert( imp->handle != BOOST_INVALID_HANDLE_VALUE ); // imp reality check
|
||||
|
||||
BOOST_SYSTEM_DIRECTORY_TYPE scratch;
|
||||
const char * name;
|
||||
if ( (name = find_next_file( imp->handle, scratch )) != 0 )
|
||||
{
|
||||
imp->entry_path.m_replace_leaf( name );
|
||||
}
|
||||
else {
|
||||
imp.reset(); // make base() the end iterator
|
||||
}
|
||||
m_imp.reset(); // make base() the end iterator
|
||||
}
|
||||
}
|
||||
|
||||
@ -251,9 +263,9 @@ namespace boost
|
||||
{
|
||||
# ifdef BOOST_POSIX
|
||||
struct stat path_stat;
|
||||
return ::stat( ph.file_path().c_str(), &path_stat ) == 0;
|
||||
return ::stat( ph.string().c_str(), &path_stat ) == 0;
|
||||
# else
|
||||
return ::GetFileAttributes( ph.file_path().c_str() ) != 0xFFFFFFFF;
|
||||
return ::GetFileAttributesA( ph.string().c_str() ) != 0xFFFFFFFF;
|
||||
# endif
|
||||
}
|
||||
|
||||
@ -261,15 +273,15 @@ namespace boost
|
||||
{
|
||||
# ifdef BOOST_POSIX
|
||||
struct stat path_stat;
|
||||
if ( ::stat( ph.directory_path().c_str(), &path_stat ) != 0 )
|
||||
throw filesystem_error( std::string("is_directory(): ")
|
||||
+ ph.directory_path().c_str(), system_error );
|
||||
if ( ::stat( ph.native_directory_string().c_str(), &path_stat ) != 0 )
|
||||
boost::throw_exception( filesystem_error( std::string("is_directory(): ")
|
||||
+ ph.native_directory_string(), system_error ) );
|
||||
return S_ISDIR( path_stat.st_mode );
|
||||
# else
|
||||
DWORD attributes = ::GetFileAttributes( ph.directory_path().c_str() );
|
||||
DWORD attributes = ::GetFileAttributesA( ph.native_directory_string().c_str() );
|
||||
if ( attributes == 0xFFFFFFFF )
|
||||
throw filesystem_error( std::string("is_directory(): ")
|
||||
+ ph.directory_path().c_str(), system_error );
|
||||
boost::throw_exception( filesystem_error( std::string("is_directory(): ")
|
||||
+ ph.native_directory_string(), system_error ) );
|
||||
return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
# endif
|
||||
}
|
||||
@ -278,19 +290,19 @@ namespace boost
|
||||
{
|
||||
# ifdef BOOST_POSIX
|
||||
struct stat path_stat;
|
||||
if ( ::stat( ph.file_path().c_str(), &path_stat ) != 0 )
|
||||
throw filesystem_error( std::string("is_empty(): ")
|
||||
+ ph.file_path().c_str(), system_error );
|
||||
if ( ::stat( ph.string().c_str(), &path_stat ) != 0 )
|
||||
boost::throw_exception( filesystem_error( std::string("is_empty(): ")
|
||||
+ ph.native_file_string(), system_error ) );
|
||||
|
||||
return S_ISDIR( path_stat.st_mode )
|
||||
? is_empty_directory( ph )
|
||||
: path_stat.st_size == 0;
|
||||
# else
|
||||
WIN32_FILE_ATTRIBUTE_DATA fad;
|
||||
if ( !::GetFileAttributesEx( ph.file_path().c_str(),
|
||||
if ( !::GetFileAttributesExA( ph.string().c_str(),
|
||||
::GetFileExInfoStandard, &fad ) )
|
||||
throw filesystem_error( std::string("is_empty(): ")
|
||||
+ ph.file_path().c_str(), system_error );
|
||||
boost::throw_exception( filesystem_error( std::string("is_empty(): ")
|
||||
+ ph.native_file_string(), system_error ) );
|
||||
|
||||
return ( fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
|
||||
? is_empty_directory( ph )
|
||||
@ -301,40 +313,42 @@ namespace boost
|
||||
void create_directory( const path & dir_path )
|
||||
{
|
||||
# ifdef BOOST_POSIX
|
||||
if ( ::mkdir( dir_path.directory_path().c_str(),
|
||||
if ( ::mkdir( dir_path.native_directory_string().c_str(),
|
||||
S_IRWXU|S_IRWXG|S_IRWXO ) != 0 )
|
||||
# else
|
||||
if ( !::CreateDirectory( dir_path.directory_path().c_str(), 0 ) )
|
||||
if ( !::CreateDirectoryA( dir_path.native_directory_string().c_str(), 0 ) )
|
||||
# endif
|
||||
throw filesystem_error( std::string("create_directory(): ")
|
||||
+ dir_path.directory_path().c_str(), system_error );
|
||||
boost::throw_exception( filesystem_error( std::string("create_directory(): ")
|
||||
+ dir_path.native_directory_string(), system_error ) );
|
||||
}
|
||||
|
||||
void remove( const path & ph )
|
||||
bool remove( const path & ph )
|
||||
{
|
||||
if ( exists( ph ) )
|
||||
{
|
||||
if ( is_directory( ph ) )
|
||||
{
|
||||
# ifdef BOOST_POSIX
|
||||
if ( ::rmdir( ph.file_path().c_str() ) != 0 )
|
||||
if ( ::rmdir( ph.string().c_str() ) != 0 )
|
||||
# else
|
||||
if ( !::RemoveDirectory( ph.file_path().c_str() ) )
|
||||
if ( !::RemoveDirectoryA( ph.string().c_str() ) )
|
||||
# endif
|
||||
throw fs::filesystem_error( std::string("remove() on: ")
|
||||
+ ph.file_path().c_str(), system_error );
|
||||
boost::throw_exception( filesystem_error( std::string("remove() on: ")
|
||||
+ ph.native_file_string(), system_error ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
# ifdef BOOST_POSIX
|
||||
if ( ::remove( ph.file_path().c_str() ) != 0 )
|
||||
if ( ::remove( ph.string().c_str() ) != 0 )
|
||||
# else
|
||||
if ( !::DeleteFile( ph.file_path().c_str() ) )
|
||||
if ( !::DeleteFileA( ph.string().c_str() ) )
|
||||
# endif
|
||||
throw fs::filesystem_error( std::string("remove() on: ")
|
||||
+ ph.file_path().c_str(), system_error );
|
||||
boost::throw_exception( filesystem_error( std::string("remove() on: ")
|
||||
+ ph.native_file_string(), system_error ) );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned long remove_all( const path & ph )
|
||||
@ -347,12 +361,13 @@ namespace boost
|
||||
{
|
||||
# ifdef BOOST_POSIX
|
||||
if ( exists( new_path ) // POSIX is too permissive so must check
|
||||
|| ::rename( old_path.file_path().c_str(), new_path.file_path().c_str() ) != 0 )
|
||||
|| ::rename( old_path.string().c_str(), new_path.string().c_str() ) != 0 )
|
||||
# else
|
||||
if ( !::MoveFile( old_path.file_path().c_str(), new_path.file_path().c_str() ) )
|
||||
if ( !::MoveFileA( old_path.string().c_str(), new_path.string().c_str() ) )
|
||||
# endif
|
||||
throw filesystem_error( std::string("move_file(): ")
|
||||
+ old_path.file_path().c_str() + ", " + new_path.file_path().c_str(), system_error );
|
||||
boost::throw_exception( filesystem_error( std::string("move_file(): ")
|
||||
+ old_path.native_file_string()
|
||||
+ ", " + new_path.native_file_string(), system_error ) );
|
||||
}
|
||||
|
||||
void copy_file( const path & from_file_ph,
|
||||
@ -365,16 +380,16 @@ namespace boost
|
||||
boost::scoped_array<char> buf( new char [buf_sz] );
|
||||
int infile, outfile;
|
||||
|
||||
if ( (infile = ::open( from_file_ph.file_path().c_str(),
|
||||
if ( (infile = ::open( from_file_ph.string().c_str(),
|
||||
O_RDONLY )) < 0
|
||||
|| (outfile = ::open( to_file_ph.file_path().c_str(),
|
||||
|| (outfile = ::open( to_file_ph.string().c_str(),
|
||||
O_WRONLY | O_CREAT | O_EXCL,
|
||||
S_IRWXU|S_IRWXG|S_IRWXO )) < 0 )
|
||||
{
|
||||
if ( infile != 0 ) ::close( infile );
|
||||
throw fs::filesystem_error( std::string("copy() files: ")
|
||||
+ from_file_ph.file_path().c_str()
|
||||
+ ", " + to_file_ph.file_path().c_str(), system_error );
|
||||
boost::throw_exception( filesystem_error( std::string("copy() files: ")
|
||||
+ from_file_ph.string()
|
||||
+ ", " + to_file_ph.string(), system_error ) );
|
||||
}
|
||||
|
||||
ssize_t sz;
|
||||
@ -386,39 +401,77 @@ namespace boost
|
||||
|
||||
if ( sz != 0 )
|
||||
# else
|
||||
if ( !::CopyFile( from_file_ph.file_path().c_str(),
|
||||
to_file_ph.file_path().c_str(), /*fail_if_exists=*/true ) )
|
||||
if ( !::CopyFileA( from_file_ph.string().c_str(),
|
||||
to_file_ph.string().c_str(), /*fail_if_exists=*/true ) )
|
||||
# endif
|
||||
throw fs::filesystem_error( std::string("copy() files: ")
|
||||
+ from_file_ph.file_path().c_str()
|
||||
+ ", " + to_file_ph.file_path().c_str(), system_error );
|
||||
boost::throw_exception( filesystem_error( std::string("copy() files: ")
|
||||
+ from_file_ph.native_file_string()
|
||||
+ ", " + to_file_ph.native_file_string(), system_error ) );
|
||||
}
|
||||
|
||||
const path & initial_directory()
|
||||
path current_path()
|
||||
{
|
||||
static path init_dir;
|
||||
if ( init_dir.is_null() )
|
||||
{
|
||||
# ifdef BOOST_POSIX
|
||||
long path_max = ::pathconf( ".", _PC_PATH_MAX );
|
||||
if ( path_max == -1 )
|
||||
throw filesystem_error( "initial_directory()" );
|
||||
boost::scoped_array<char>
|
||||
buf( new char[static_cast<std::size_t>(path_max)] );
|
||||
if ( ::getcwd( buf.get(), static_cast<std::size_t>(path_max) ) == 0 )
|
||||
# else
|
||||
DWORD sz;
|
||||
if ( (sz = ::GetCurrentDirectory( 0, static_cast<char*>(0) )) == 0 )
|
||||
throw filesystem_error( "initial_directory()" );
|
||||
boost::scoped_array<char> buf( new char[sz] );
|
||||
if ( ::GetCurrentDirectory( sz, buf.get() ) == 0 )
|
||||
# endif
|
||||
{ throw filesystem_error( "initial_directory()", system_error ); }
|
||||
init_dir = path( buf.get(), system_specific );
|
||||
}
|
||||
return init_dir;
|
||||
# ifdef BOOST_POSIX
|
||||
long path_max = ::pathconf( ".", _PC_PATH_MAX );
|
||||
if ( path_max < 1 )
|
||||
boost::throw_exception(
|
||||
filesystem_error( "initial_path(): size < 1", other_error ) );
|
||||
boost::scoped_array<char>
|
||||
buf( new char[static_cast<std::size_t>(path_max)] );
|
||||
if ( ::getcwd( buf.get(), static_cast<std::size_t>(path_max) ) == 0 )
|
||||
# else
|
||||
DWORD sz;
|
||||
if ( (sz = ::GetCurrentDirectoryA( 0, static_cast<char*>(0) )) == 0 )
|
||||
boost::throw_exception(
|
||||
filesystem_error( "initial_path(): size is zero", other_error ) );
|
||||
boost::scoped_array<char> buf( new char[sz] );
|
||||
if ( ::GetCurrentDirectoryA( sz, buf.get() ) == 0 )
|
||||
# endif
|
||||
{ boost::throw_exception(
|
||||
filesystem_error( "initial_path()", system_error ) ); }
|
||||
return path( buf.get(), native );
|
||||
}
|
||||
|
||||
const path & initial_path()
|
||||
{
|
||||
static path init_path;
|
||||
if ( init_path.empty() ) init_path = current_path();
|
||||
return init_path;
|
||||
}
|
||||
|
||||
path system_complete( const path & ph )
|
||||
{
|
||||
if ( ph.empty() ) return ph;
|
||||
# ifdef BOOST_WINDOWS
|
||||
char buf[MAX_PATH];
|
||||
char * pfn;
|
||||
std::size_t len = ::GetFullPathNameA( ph.string().c_str(),
|
||||
sizeof(buf) , buf, &pfn );
|
||||
if ( !len )
|
||||
{ boost::throw_exception(
|
||||
filesystem_error( "system_complete()", system_error ) ); }
|
||||
buf[len] = '\0';
|
||||
return path( buf, native );
|
||||
# else
|
||||
return current_path() / ph;
|
||||
# endif
|
||||
}
|
||||
|
||||
path complete( const path & ph, const path & base )
|
||||
{
|
||||
assert( base.is_complete()
|
||||
&& (ph.is_complete() || !ph.has_root_name()) ); // precondition
|
||||
# ifdef BOOST_WINDOWS
|
||||
if (ph.empty() || ph.is_complete()) return ph;
|
||||
if ( !ph.has_root_name() )
|
||||
return ph.has_root_directory()
|
||||
? path( base.root_name(), native ) / ph
|
||||
: base / ph;
|
||||
return base / ph;
|
||||
# else
|
||||
return (ph.empty() || ph.is_complete()) ? ph : base / ph;
|
||||
# endif
|
||||
}
|
||||
} // namespace filesystem
|
||||
} // namespace boost
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
// without express or implied warranty, and with no claim as to its
|
||||
// suitability for any purpose.
|
||||
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
// See http://www.boost.org/libs/filesystem for documentation.
|
||||
|
||||
|
||||
//****************************************************************************//
|
||||
@ -40,6 +40,7 @@ namespace fs = boost::filesystem;
|
||||
namespace std { using ::strlen; }
|
||||
#endif
|
||||
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <cstring> // SGI MIPSpro compilers need this
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
@ -50,22 +51,17 @@ namespace
|
||||
{
|
||||
// POSIX & Windows cases: "", "/", "/foo", "foo", "foo/bar"
|
||||
// Windows only cases: "c:", "c:/", "c:foo", "c:/foo",
|
||||
// "prn:", "//share", "//share/foo"
|
||||
// "prn:", "//share", "//share/", "//share/foo"
|
||||
|
||||
std::string::size_type leaf_pos( const std::string & str,
|
||||
std::string::size_type end_pos ) // end_pos is past-the-end position
|
||||
// return 0 if str itself is leaf (or empty)
|
||||
{
|
||||
if ( (end_pos == 1 && str[0] == '/')
|
||||
# ifdef BOOST_WINDOWS
|
||||
|| (end_pos > 1 // drive or device
|
||||
&& (str[end_pos-1] == ':' || str[end_pos-2] == ':'))
|
||||
# endif
|
||||
) return 0;
|
||||
|
||||
if ( end_pos && str[end_pos-1] == '/' ) return end_pos-1;
|
||||
|
||||
std::string::size_type pos( str.find_last_of( '/', end_pos-1 ) );
|
||||
# ifdef BOOST_WINDOWS
|
||||
if ( pos == std::string::npos ) pos = str.find_last_of( ':', end_pos-1 );
|
||||
if ( pos == std::string::npos ) pos = str.find_last_of( ':', end_pos-2 );
|
||||
# endif
|
||||
|
||||
return ( pos == std::string::npos // path itself must be a leaf (or empty)
|
||||
@ -99,8 +95,6 @@ namespace
|
||||
if ( *itr == ':' )
|
||||
{
|
||||
target += *itr++;
|
||||
if ( itr == src.end() ) return;
|
||||
if ( *itr == '/' ) { target += *itr++; }
|
||||
return;
|
||||
}
|
||||
# endif
|
||||
@ -137,7 +131,6 @@ namespace boost
|
||||
|
||||
// error checking functions --------------------------------------------//
|
||||
|
||||
|
||||
bool generic_name( const std::string & name )
|
||||
{
|
||||
return name.size() != 0
|
||||
@ -157,8 +150,8 @@ namespace boost
|
||||
const path & check_posix_leaf( const path & ph )
|
||||
{
|
||||
if ( !posix_name( ph.leaf() ) )
|
||||
throw filesystem_error( "invalid posix name: \""
|
||||
+ ph.leaf() + "\"" );
|
||||
boost::throw_exception( filesystem_error( "invalid posix name: \""
|
||||
+ ph.leaf() + "\"", path_error ) );
|
||||
return ph;
|
||||
}
|
||||
|
||||
@ -175,7 +168,7 @@ namespace boost
|
||||
&& name.find_first_not_of( valid_boost_directory ) == std::string::npos;
|
||||
}
|
||||
|
||||
// path implementation -------------------------------------------------//
|
||||
// path implementation -----------------------------------------------------//
|
||||
|
||||
path::path( const std::string & src )
|
||||
{
|
||||
@ -197,7 +190,7 @@ namespace boost
|
||||
m_path_append( src, platform );
|
||||
}
|
||||
|
||||
path & path::operator <<=( const path & rhs )
|
||||
path & path::operator /=( const path & rhs )
|
||||
{
|
||||
m_path_append( rhs.m_path, nocheck );
|
||||
return *this;
|
||||
@ -215,31 +208,57 @@ namespace boost
|
||||
|
||||
std::string::const_iterator itr( src.begin() );
|
||||
|
||||
// system-specific-root like drive: or first slash of //share
|
||||
if ( context != generic )
|
||||
// [root-filesystem]
|
||||
# ifdef BOOST_WINDOWS
|
||||
if ( context != generic && src.size() >= 2 )
|
||||
{
|
||||
if ( *itr == '/'
|
||||
// drive or device
|
||||
if ( src[1] == ':' || src[src.size()-1] == ':' )
|
||||
{
|
||||
for ( ; *itr != ':'; ++itr ) m_path += *itr;
|
||||
m_path += ':';
|
||||
++itr;
|
||||
}
|
||||
|
||||
// share
|
||||
else if ( (*itr == '/' || (*itr == '\\' && context == platform))
|
||||
&& (*(itr+1) == '/' || (*(itr+1) == '\\' && context == platform)) )
|
||||
{
|
||||
m_path += "//";
|
||||
for ( itr += 2;
|
||||
itr != src.end() && *itr != '/' && *itr != '\\';
|
||||
++itr ) m_path += *itr;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
// root directory [ "/" ]
|
||||
if ( itr != src.end() && (*itr == '/'
|
||||
# ifdef BOOST_WINDOWS
|
||||
|| (*itr == '\\' && context == platform)
|
||||
# endif
|
||||
) { ++itr; m_path += '/'; }
|
||||
else if ( itr+1 != src.end() && *(itr+1) == ':' )
|
||||
{ m_path += *itr++; m_path += *itr++; }
|
||||
|
||||
# ifdef BOOST_WINDOWS
|
||||
// "/" or second slash of //share
|
||||
if ( *itr == '/' || (*itr == '\\' && context == platform) )
|
||||
{ ++itr; m_path += '/';}
|
||||
# endif
|
||||
|
||||
if ( itr == src.end() ) return;
|
||||
) )
|
||||
{
|
||||
++itr;
|
||||
if ( m_path.size() == 0
|
||||
# ifdef BOOST_WINDOWS
|
||||
|| m_path[m_path.size()-1] == ':' // drive or device
|
||||
|| ( // share
|
||||
m_path.size() > 2
|
||||
&& m_path[0] == '/'
|
||||
&& m_path[1] == '/'
|
||||
&& m_path.find( '/', 2 ) == std::string::npos
|
||||
)
|
||||
# endif
|
||||
) m_path += '/';
|
||||
}
|
||||
|
||||
// relative-path ::= element { "/" element }
|
||||
// element { "/" element } [ "/" ]
|
||||
while ( itr != src.end() )
|
||||
{
|
||||
|
||||
// append '/' if needed
|
||||
if ( !is_null() // append '/'
|
||||
if ( !empty()
|
||||
&& *(m_path.end()-1) != ':' && *(m_path.end()-1) != '/' )
|
||||
m_path += '/';
|
||||
|
||||
@ -278,7 +297,7 @@ namespace boost
|
||||
++itr;
|
||||
++itr;
|
||||
} // ".."
|
||||
else // name
|
||||
else // element is name
|
||||
{
|
||||
std::string name;
|
||||
do
|
||||
@ -291,31 +310,49 @@ namespace boost
|
||||
|
||||
if ( context == generic && !generic_name( name ) )
|
||||
{
|
||||
throw filesystem_error( "invalid path name: \""
|
||||
+ src + "\"" );
|
||||
boost::throw_exception( filesystem_error( "invalid path name: \""
|
||||
+ src + "\"", path_error ) );
|
||||
}
|
||||
|
||||
m_path += name;
|
||||
}
|
||||
|
||||
if ( itr != src.end() )
|
||||
{
|
||||
if ( !( (*itr == '/'
|
||||
# ifdef BOOST_WINDOWS
|
||||
|| (context == platform && *itr == '\\')
|
||||
# endif
|
||||
) && (itr+1) != src.end() ) )
|
||||
{
|
||||
throw filesystem_error( "invalid path syntax: \""
|
||||
+ src + "\"" );
|
||||
}
|
||||
++itr;
|
||||
{
|
||||
if ( *itr == '/'
|
||||
# ifdef BOOST_WINDOWS
|
||||
|| (*itr == '\\' && context == platform)
|
||||
# endif
|
||||
) ++itr;
|
||||
else
|
||||
boost::throw_exception( filesystem_error( "invalid path syntax: \""
|
||||
+ src + "\"", path_error ) );
|
||||
}
|
||||
|
||||
} // while more elements
|
||||
}
|
||||
|
||||
const path::iterator path::begin() const
|
||||
// path conversion functions ------------------------------------------------//
|
||||
|
||||
std::string path::native_file_string() const
|
||||
{
|
||||
# ifdef BOOST_WINDOWS
|
||||
std::string s( m_path );
|
||||
for ( std::string::iterator itr( s.begin() );
|
||||
itr != s.end(); ++itr )
|
||||
if ( *itr == '/' ) *itr = '\\';
|
||||
return s;
|
||||
# else
|
||||
return m_path;
|
||||
# endif
|
||||
}
|
||||
|
||||
std::string path::native_directory_string() const
|
||||
{ return native_file_string(); }
|
||||
|
||||
// path decomposition functions ---------------------------------------------//
|
||||
|
||||
path::iterator path::begin() const
|
||||
{
|
||||
iterator itr;
|
||||
itr.base().path_ptr = this;
|
||||
@ -330,35 +367,167 @@ namespace boost
|
||||
m_path += new_leaf;
|
||||
}
|
||||
|
||||
const std::string path::leaf() const
|
||||
std::string path::leaf() const
|
||||
{
|
||||
return m_path.substr( leaf_pos( m_path, m_path.size() ) );
|
||||
}
|
||||
|
||||
const path path::branch() const
|
||||
namespace detail
|
||||
{
|
||||
std::string::size_type len( leaf_pos( m_path, m_path.size() ) );
|
||||
|
||||
if ( len > 1 // unless delimiter is part of root, don't include it
|
||||
# ifdef BOOST_WINDOWS
|
||||
&& m_path[len-1] != ':'
|
||||
&& m_path[len-2] != ':'
|
||||
# endif
|
||||
) --len;
|
||||
|
||||
return path( m_path.substr( 0, len ), system_specific );
|
||||
inline bool is_absolute_root( const std::string & s,
|
||||
std::string::size_type len )
|
||||
{
|
||||
return
|
||||
len && s[len-1] == '/'
|
||||
&&
|
||||
(
|
||||
len == 1 // "/"
|
||||
# ifdef BOOST_WINDOWS
|
||||
|| ( len > 1
|
||||
&& ( s[len-2] == ':' // drive or device
|
||||
|| ( s[0] == '/' // share
|
||||
&& s[1] == '/'
|
||||
&& s.find( '/', 2 ) == len-1
|
||||
)
|
||||
)
|
||||
)
|
||||
# endif
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//bool path::is_absolute() const
|
||||
//{
|
||||
// return ( m_path.size()
|
||||
// && m_path[0] == '/' ) // covers both "/" and "//share"
|
||||
// || ( m_path.size() > 2
|
||||
// && m_path[1] == ':'
|
||||
// && m_path[2] == '/' ) // "c:/"
|
||||
// || ( m_path.size() > 3
|
||||
// && m_path[m_path.size()-1] == ':' ); // "device:"
|
||||
//}
|
||||
path path::branch_path() const
|
||||
{
|
||||
std::string::size_type end_pos( leaf_pos( m_path, m_path.size() ) );
|
||||
|
||||
// skip a '/' unless it is a root directory
|
||||
if ( end_pos && m_path[end_pos-1] == '/'
|
||||
&& !detail::is_absolute_root( m_path, end_pos ) ) --end_pos;
|
||||
return path( m_path.substr( 0, end_pos ), native );
|
||||
}
|
||||
|
||||
path path::relative_path() const
|
||||
{
|
||||
std::string::size_type pos( 0 );
|
||||
if ( m_path.size() && m_path[0] == '/' )
|
||||
{ pos = 1;
|
||||
# ifdef BOOST_WINDOWS
|
||||
if ( m_path.size()>1 && m_path[1] == '/' ) // share
|
||||
{
|
||||
if ( (pos = m_path.find( '/', 2 )) != std::string::npos ) ++pos;
|
||||
else return path();
|
||||
}
|
||||
}
|
||||
else if ( (pos = m_path.find( ':' )) == std::string::npos ) pos = 0;
|
||||
else // has ':'
|
||||
{
|
||||
if ( ++pos < m_path.size() && m_path[pos] == '/' ) ++pos;
|
||||
# endif
|
||||
}
|
||||
return path( m_path.substr( pos ) );
|
||||
}
|
||||
|
||||
std::string path::root_name() const
|
||||
{
|
||||
# ifdef BOOST_WINDOWS
|
||||
std::string::size_type pos( m_path.find( ':' ) );
|
||||
if ( pos != std::string::npos ) return m_path.substr( 0, pos+1 );
|
||||
if ( m_path.size() > 2 && m_path[0] == '/' && m_path[1] == '/' )
|
||||
{
|
||||
pos = m_path.find( '/', 2 );
|
||||
return m_path.substr( 0, pos );
|
||||
}
|
||||
# endif
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string path::root_directory() const
|
||||
{
|
||||
return std::string(
|
||||
( m_path.size() && m_path[0] == '/' ) // covers both "/" and "//share"
|
||||
# ifdef BOOST_WINDOWS
|
||||
|| ( m_path.size() > 2
|
||||
&& m_path[1] == ':'
|
||||
&& m_path[2] == '/' ) // "c:/"
|
||||
# endif
|
||||
? "/" : "" );
|
||||
}
|
||||
|
||||
path path::root_path() const
|
||||
{
|
||||
return path(
|
||||
# ifdef BOOST_WINDOWS
|
||||
root_name(), native ) /= root_directory();
|
||||
# else
|
||||
root_directory() );
|
||||
# endif
|
||||
}
|
||||
|
||||
// path query functions -----------------------------------------------------//
|
||||
|
||||
bool path::is_complete() const
|
||||
{
|
||||
# ifdef BOOST_WINDOWS
|
||||
return m_path.size() > 2
|
||||
&& ( (m_path[1] == ':' && m_path[2] == '/') // "c:/"
|
||||
|| (m_path[0] == '/' && m_path[1] == '/') // "//share"
|
||||
|| m_path[m_path.size()-1] == ':' );
|
||||
# else
|
||||
return m_path.size() && m_path[0] == '/';
|
||||
# endif
|
||||
|
||||
|
||||
return ( m_path.size()
|
||||
&& m_path[0] == '/' ) // covers both "/" and "//share"
|
||||
# ifdef BOOST_WINDOWS
|
||||
|| ( m_path.size() > 1 && m_path[1] == ':' ) // "c:" and "c:/"
|
||||
|| ( m_path.size() > 3
|
||||
&& m_path[m_path.size()-1] == ':' ) // "device:"
|
||||
# endif
|
||||
;
|
||||
}
|
||||
|
||||
bool path::has_root_path() const
|
||||
{
|
||||
return ( m_path.size()
|
||||
&& m_path[0] == '/' ) // covers both "/" and "//share"
|
||||
# ifdef BOOST_WINDOWS
|
||||
|| ( m_path.size() > 1 && m_path[1] == ':' ) // "c:" and "c:/"
|
||||
|| ( m_path.size() > 3
|
||||
&& m_path[m_path.size()-1] == ':' ) // "device:"
|
||||
# endif
|
||||
;
|
||||
}
|
||||
|
||||
bool path::has_root_name() const
|
||||
{
|
||||
# ifdef BOOST_WINDOWS
|
||||
return m_path.size() > 1
|
||||
&& ( m_path[1] == ':' // "c:"
|
||||
|| m_path[m_path.size()-1] == ':' // "prn:"
|
||||
|| (m_path[0] == '/' && m_path[1] == '/') // "//share"
|
||||
);
|
||||
# else
|
||||
return false;
|
||||
# endif
|
||||
}
|
||||
|
||||
bool path::has_root_directory() const
|
||||
{
|
||||
return ( m_path.size()
|
||||
&& m_path[0] == '/' ) // covers both "/" and "//share"
|
||||
# ifdef BOOST_WINDOWS
|
||||
|| ( m_path.size() > 2
|
||||
&& m_path[1] == ':' && m_path[2] == '/' ) // "c:/"
|
||||
# endif
|
||||
;
|
||||
}
|
||||
|
||||
bool path::has_relative_path() const { return !relative_path().empty(); }
|
||||
bool path::has_branch_path() const { return !branch_path().empty(); }
|
||||
|
||||
|
||||
// path_itr_imp implementation ----------------------------------------------//
|
||||
|
||||
namespace detail
|
||||
{
|
||||
@ -371,7 +540,18 @@ namespace boost
|
||||
name = ""; // not strictly required, but might aid debugging
|
||||
return;
|
||||
}
|
||||
if ( path_ptr->m_path[pos] == '/' ) ++pos;
|
||||
if ( path_ptr->m_path[pos] == '/' )
|
||||
{
|
||||
# ifdef BOOST_WINDOWS
|
||||
if ( name[name.size()-1] == ':' // drive or device
|
||||
|| (name[0] == '/' && name[1] == '/') ) // share
|
||||
{
|
||||
name = "/";
|
||||
return;
|
||||
}
|
||||
# endif
|
||||
++pos;
|
||||
}
|
||||
std::string::size_type end_pos( path_ptr->m_path.find( '/', pos ) );
|
||||
if ( end_pos == std::string::npos ) end_pos = path_ptr->m_path.size();
|
||||
name = path_ptr->m_path.substr( pos, end_pos - pos );
|
||||
@ -381,13 +561,10 @@ namespace boost
|
||||
{
|
||||
assert( pos ); // detect decrement of begin
|
||||
std::string::size_type end_pos( pos );
|
||||
if ( end_pos != path_ptr->m_path.size()
|
||||
&& end_pos > 1
|
||||
# ifdef BOOST_WINDOWS
|
||||
&& path_ptr->m_path[end_pos-1] != ':'
|
||||
&& path_ptr->m_path[end_pos-2] != ':'
|
||||
# endif
|
||||
) --end_pos;
|
||||
|
||||
// skip a '/' unless it is a root directory
|
||||
if ( path_ptr->m_path[end_pos-1] == '/'
|
||||
&& !detail::is_absolute_root( path_ptr->m_path, end_pos ) ) --end_pos;
|
||||
pos = leaf_pos( path_ptr->m_path, end_pos );
|
||||
name = path_ptr->m_path.substr( pos, end_pos - pos );
|
||||
}
|
||||
|
@ -13,19 +13,15 @@ include testing.jam ;
|
||||
test-suite "filesystem"
|
||||
: [ run libs/filesystem/test/path_test.cpp
|
||||
<lib>../../../libs/filesystem/build/fs
|
||||
<lib>../../../libs/test/build/test_exec_monitor
|
||||
]
|
||||
[ run libs/filesystem/test/operations_test.cpp
|
||||
<lib>../../../libs/filesystem/build/fs
|
||||
<lib>../../../libs/test/build/test_exec_monitor
|
||||
]
|
||||
[ run libs/filesystem/test/fstream_test.cpp
|
||||
<lib>../../../libs/filesystem/build/fs
|
||||
<lib>../../../libs/test/build/test_exec_monitor
|
||||
]
|
||||
# [ run libs/filesystem/test/recursive_dir_itr_test.cpp
|
||||
# <lib>../../../libs/filesystem/build/fs
|
||||
# <lib>../../../libs/test/build/test_exec_monitor
|
||||
# ]
|
||||
;
|
||||
}
|
||||
|
@ -18,9 +18,7 @@ namespace fs = boost::filesystem;
|
||||
namespace std { using ::remove; }
|
||||
#endif
|
||||
|
||||
|
||||
#define BOOST_INCLUDE_MAIN
|
||||
#include <boost/test/test_tools.hpp>
|
||||
#include <boost/test/minimal.hpp>
|
||||
|
||||
int test_main( int, char*[] )
|
||||
{
|
||||
|
@ -12,9 +12,8 @@
|
||||
#include <boost/filesystem/exception.hpp>
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
//#include <boost/test/test_tools.hpp>
|
||||
#include <boost/test/minimal.hpp>
|
||||
|
||||
#include <boost/concept_check.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
using boost::bind;
|
||||
|
||||
@ -24,40 +23,46 @@ using boost::bind;
|
||||
|
||||
namespace
|
||||
{
|
||||
bool report_throws;
|
||||
fs::directory_iterator end_itr;
|
||||
|
||||
void create_file( const fs::path & ph, const std::string & contents )
|
||||
{
|
||||
std::ofstream f( ph.file_path().c_str() );
|
||||
std::ofstream f( ph.native_file_string().c_str() );
|
||||
if ( !f )
|
||||
throw fs::filesystem_error( "ofstream(): " + ph.generic_path() );
|
||||
throw fs::filesystem_error( "ofstream(): " + ph.string(),
|
||||
fs::system_error );
|
||||
if ( !contents.empty() ) f << contents;
|
||||
}
|
||||
|
||||
void verify_file( const fs::path & ph, const std::string & expected )
|
||||
{
|
||||
std::ifstream f( ph.file_path().c_str() );
|
||||
std::ifstream f( ph.native_file_string().c_str() );
|
||||
if ( !f )
|
||||
throw fs::filesystem_error( "ifstream(): " + ph.generic_path() );
|
||||
throw fs::filesystem_error( "ifstream(): " + ph.string(),
|
||||
fs::system_error );
|
||||
std::string contents;
|
||||
f >> contents;
|
||||
if ( contents != expected )
|
||||
throw fs::filesystem_error("verify_file(): " + ph.generic_path()
|
||||
throw fs::filesystem_error("verify_file(): " + ph.string()
|
||||
+ " contents \"" + contents
|
||||
+ "\" != \"" + expected + "\"" );
|
||||
+ "\" != \"" + expected + "\"", fs::system_error );
|
||||
}
|
||||
|
||||
template< typename F >
|
||||
bool throws_fs_error( F func )
|
||||
bool throws_fs_error( F func, fs::error_code ec = fs::no_error )
|
||||
{
|
||||
try { func(); }
|
||||
|
||||
catch ( const fs::filesystem_error & /*ex*/ )
|
||||
catch ( const fs::filesystem_error & ex )
|
||||
{
|
||||
// std::cout << ex.what() << "\n";
|
||||
return true;
|
||||
if ( report_throws ) std::cout << ex.what() << "\n";
|
||||
if ( ec == fs::no_error || ec == ex.error() ) return true;
|
||||
std::cout << "filesystem_error::error() reports " << ex.error()
|
||||
<< ", should be " << ec
|
||||
<< "\n native_error() is " << ex.native_error()
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -65,29 +70,88 @@ namespace
|
||||
|
||||
// test_main ---------------------------------------------------------------//
|
||||
|
||||
int test_main( int, char * [] )
|
||||
int test_main( int argc, char * argv[] )
|
||||
{
|
||||
if ( argc > 1 && *argv[1]=='-' && *(argv[1]+1)=='t' ) report_throws = true;
|
||||
|
||||
std::cout << "implemenation name: "
|
||||
<< fs::detail::implementation_name() << "\n";
|
||||
std::cout << "initial_directory() is \""
|
||||
<< fs::initial_directory().generic_path()
|
||||
std::cout << "initial_path().string() is\n \""
|
||||
<< fs::initial_path().string()
|
||||
<< "\"\n";
|
||||
std::cout << "initial_path().native_file_string() is\n \""
|
||||
<< fs::initial_path().native_file_string()
|
||||
<< "\"\n";
|
||||
|
||||
fs::path dir( fs::initial_directory() << "temp_fs_test_directory" );
|
||||
BOOST_TEST( fs::initial_path().is_complete() );
|
||||
BOOST_TEST( fs::current_path().is_complete() );
|
||||
BOOST_TEST( fs::initial_path().string() == fs::current_path().string() );
|
||||
|
||||
BOOST_TEST( fs::complete( "" ).empty() );
|
||||
BOOST_TEST( fs::complete( "/" ).string()
|
||||
== fs::initial_path().root_path().string() );
|
||||
BOOST_TEST( fs::complete( "foo" ).string()
|
||||
== fs::initial_path().string()+"/foo" );
|
||||
BOOST_TEST( fs::complete( "/foo" ).string()
|
||||
== fs::initial_path().root_path().string()+"foo" );
|
||||
|
||||
fs::path dir( fs::initial_path() / "temp_fs_test_directory" );
|
||||
|
||||
// Windows only tests
|
||||
if ( std::strcmp( fs::detail::implementation_name(), "Windows" ) == 0 )
|
||||
{
|
||||
BOOST_TEST( dir.generic_path().size() > 1
|
||||
&& dir.generic_path()[1] == ':' ); // verify path includes drive
|
||||
BOOST_TEST( dir.string().size() > 1
|
||||
&& dir.string()[1] == ':' ); // verify path includes drive
|
||||
|
||||
BOOST_TEST( fs::system_complete( "" ).empty() );
|
||||
BOOST_TEST( fs::system_complete( "/" ).string()
|
||||
== fs::initial_path().root_path().string() );
|
||||
BOOST_TEST( fs::system_complete( "foo" ).string()
|
||||
== fs::initial_path().string()+"/foo" );
|
||||
BOOST_TEST( fs::system_complete( "/foo" ).string()
|
||||
== fs::initial_path().root_path().string()+"foo" );
|
||||
|
||||
// BOOST_TEST( fs::complete( fs::path( "c:", fs::native ) ).string()
|
||||
// == fs::initial_path().string() );
|
||||
// BOOST_TEST( fs::complete( fs::path( "c:foo", fs::native ) ).string()
|
||||
// == fs::initial_path().string()+"/foo" );
|
||||
BOOST_TEST( fs::complete( fs::path( "c:/", fs::native ) ).string()
|
||||
== "c:/" );
|
||||
BOOST_TEST( fs::complete( fs::path( "c:/foo", fs::native ) ).string()
|
||||
== "c:/foo" );
|
||||
BOOST_TEST( fs::complete( fs::path( "//share", fs::native ) ).string()
|
||||
== "//share" );
|
||||
|
||||
BOOST_TEST( fs::system_complete( fs::path( "c:", fs::native ) ).string()
|
||||
== fs::initial_path().string() );
|
||||
BOOST_TEST( fs::system_complete( fs::path( "c:foo", fs::native ) ).string()
|
||||
== fs::initial_path().string()+"/foo" );
|
||||
BOOST_TEST( fs::system_complete( fs::path( "c:/", fs::native ) ).string()
|
||||
== "c:/" );
|
||||
BOOST_TEST( fs::system_complete( fs::path( "c:/foo", fs::native ) ).string()
|
||||
== "c:/foo" );
|
||||
BOOST_TEST( fs::system_complete( fs::path( "//share", fs::native ) ).string()
|
||||
== "//share" );
|
||||
}
|
||||
|
||||
fs::path ng( " no-way, Jose ", fs::system_specific );
|
||||
else if ( std::strcmp( fs::detail::implementation_name(), "POSIX" ) == 0 )
|
||||
{
|
||||
BOOST_TEST( fs::system_complete( "" ).empty() );
|
||||
BOOST_TEST( fs::system_complete( "/" ).string()
|
||||
== fs::initial_path().root_path().string() );
|
||||
BOOST_TEST( fs::system_complete( "foo" ).string()
|
||||
== fs::initial_path().string()+"/foo" );
|
||||
BOOST_TEST( fs::system_complete( "/foo" ).string()
|
||||
== fs::initial_path().root_path().string()+"foo" );
|
||||
}
|
||||
|
||||
fs::path ng( " no-way, Jose ", fs::native );
|
||||
|
||||
fs::remove_all( dir ); // in case residue from prior failed tests
|
||||
BOOST_TEST( !fs::exists( dir ) );
|
||||
|
||||
// the bound functions should throw, so throws_fs_error() should return true
|
||||
BOOST_TEST( throws_fs_error( bind( fs::is_directory, ng ) ) );
|
||||
BOOST_TEST( throws_fs_error( bind( fs::is_directory, ng ), fs::not_found_error ) );
|
||||
BOOST_TEST( throws_fs_error( bind( fs::is_directory, dir ) ) );
|
||||
BOOST_TEST( throws_fs_error( bind( fs::_is_empty, dir ) ) );
|
||||
|
||||
@ -98,19 +162,21 @@ int test_main( int, char * [] )
|
||||
|
||||
BOOST_TEST( fs::is_directory( dir ) );
|
||||
|
||||
fs::path d1( dir << "d1" );
|
||||
fs::path d1( dir / "d1" );
|
||||
fs::create_directory( d1 );
|
||||
BOOST_TEST( fs::exists( d1 ) );
|
||||
BOOST_TEST( fs::is_directory( d1 ) );
|
||||
BOOST_TEST( fs::_is_empty( d1 ) );
|
||||
|
||||
boost::function_requires< boost::InputIteratorConcept< fs::directory_iterator > >();
|
||||
|
||||
{
|
||||
fs::directory_iterator dir_itr( dir );
|
||||
BOOST_TEST( dir_itr->leaf() == "d1" );
|
||||
}
|
||||
|
||||
// create a second directory named d2
|
||||
fs::path d2( dir << "d2" );
|
||||
fs::path d2( dir / "d2" );
|
||||
fs::create_directory(d2 );
|
||||
BOOST_TEST( fs::exists( d2 ) );
|
||||
BOOST_TEST( fs::is_directory( d2 ) );
|
||||
@ -120,26 +186,38 @@ int test_main( int, char * [] )
|
||||
BOOST_TEST( dir_itr->leaf() == "d1" || dir_itr->leaf() == "d2" );
|
||||
if ( dir_itr->leaf() == "d1" )
|
||||
{
|
||||
// Thomas Witt suggested the ++ to verify a compiler problem workaround
|
||||
// BOOST_TEST( (++fs::directory_iterator(dir))->leaf() == "d2" );
|
||||
++dir_itr;
|
||||
BOOST_TEST( (++dir_itr)->leaf() == "d2" );
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_TEST( (++dir_itr)->leaf() == "d1" );
|
||||
}
|
||||
}
|
||||
|
||||
{ // *i++ must work to meet the standard's InputIterator requirements
|
||||
fs::directory_iterator dir_itr( dir );
|
||||
BOOST_TEST( dir_itr->leaf() == "d1" || dir_itr->leaf() == "d2" );
|
||||
if ( dir_itr->leaf() == "d1" )
|
||||
{
|
||||
BOOST_TEST( (*dir_itr++).leaf() == "d1" );
|
||||
BOOST_TEST( dir_itr->leaf() == "d2" );
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_TEST( (++fs::directory_iterator(dir))->leaf() == "d1" );
|
||||
BOOST_TEST( (*dir_itr++).leaf() == "d2" );
|
||||
BOOST_TEST( dir_itr->leaf() == "d1" );
|
||||
}
|
||||
}
|
||||
|
||||
// create an empty file named "f0"
|
||||
fs::path file_ph( dir << "f0");
|
||||
fs::path file_ph( dir / "f0");
|
||||
create_file( file_ph, "" );
|
||||
BOOST_TEST( fs::exists( file_ph ) );
|
||||
BOOST_TEST( !fs::is_directory( file_ph ) );
|
||||
BOOST_TEST( fs::_is_empty( file_ph ) );
|
||||
|
||||
// create a file named "f1"
|
||||
file_ph = dir << "f1";
|
||||
file_ph = dir / "f1";
|
||||
create_file( file_ph, "foobar1" );
|
||||
BOOST_TEST( fs::exists( file_ph ) );
|
||||
BOOST_TEST( !fs::is_directory( file_ph ) );
|
||||
@ -154,58 +232,59 @@ int test_main( int, char * [] )
|
||||
}
|
||||
|
||||
// copy_file() tests
|
||||
fs::copy_file( file_ph, d1 << "f2" );
|
||||
fs::copy_file( file_ph, d1 / "f2" );
|
||||
BOOST_TEST( fs::exists( file_ph ) );
|
||||
BOOST_TEST( fs::exists( d1 << "f2" ) );
|
||||
BOOST_TEST( !fs::is_directory( d1 << "f2" ) );
|
||||
verify_file( d1 << "f2", "foobar1" );
|
||||
BOOST_TEST( fs::exists( d1 / "f2" ) );
|
||||
BOOST_TEST( !fs::is_directory( d1 / "f2" ) );
|
||||
verify_file( d1 / "f2", "foobar1" );
|
||||
|
||||
// rename() on file d1/f2 to d2/f3
|
||||
fs::rename( d1 << "f2", d2 << "f3" );
|
||||
BOOST_TEST( !fs::exists( d1 << "f2" ) );
|
||||
BOOST_TEST( !fs::exists( d2 << "f2" ) );
|
||||
BOOST_TEST( fs::exists( d2 << "f3" ) );
|
||||
BOOST_TEST( !fs::is_directory( d2 << "f3" ) );
|
||||
verify_file( d2 << "f3", "foobar1" );
|
||||
fs::rename( d1 / "f2", d2 / "f3" );
|
||||
BOOST_TEST( !fs::exists( d1 / "f2" ) );
|
||||
BOOST_TEST( !fs::exists( d2 / "f2" ) );
|
||||
BOOST_TEST( fs::exists( d2 / "f3" ) );
|
||||
BOOST_TEST( !fs::is_directory( d2 / "f3" ) );
|
||||
verify_file( d2 / "f3", "foobar1" );
|
||||
|
||||
// make sure can't rename() a non-existent file
|
||||
BOOST_TEST( throws_fs_error( bind( fs::rename, d1 << "f2", d2 << "f4" ) ) );
|
||||
BOOST_TEST( throws_fs_error( bind( fs::rename, d1 / "f2", d2 / "f4" ) ) );
|
||||
|
||||
// make sure can't rename() to an existent file
|
||||
BOOST_TEST( throws_fs_error( bind( fs::rename, dir << "f1", d2 << "f3" ) ) );
|
||||
BOOST_TEST( throws_fs_error( bind( fs::rename, dir / "f1", d2 / "f3" ),
|
||||
fs::already_exists_error ) );
|
||||
|
||||
// make sure can't rename() to a nonexistent parent directory
|
||||
BOOST_TEST( throws_fs_error( bind( fs::rename, dir << "f1", dir << "d3/f3" ) ) );
|
||||
BOOST_TEST( throws_fs_error( bind( fs::rename, dir / "f1", dir / "d3/f3" ) ) );
|
||||
|
||||
// rename() on directory
|
||||
fs::path d3( dir << "d3" );
|
||||
fs::path d3( dir / "d3" );
|
||||
fs::rename( d2, d3 );
|
||||
BOOST_TEST( !fs::exists( d2 ) );
|
||||
BOOST_TEST( fs::exists( d3 ) );
|
||||
BOOST_TEST( fs::is_directory( d3 ) );
|
||||
BOOST_TEST( !fs::exists( d2 << "f3" ) );
|
||||
BOOST_TEST( fs::exists( d3 << "f3" ) );
|
||||
BOOST_TEST( !fs::exists( d2 / "f3" ) );
|
||||
BOOST_TEST( fs::exists( d3 / "f3" ) );
|
||||
|
||||
// remove() tests on file
|
||||
file_ph = dir << "shortlife";
|
||||
file_ph = dir / "shortlife";
|
||||
BOOST_TEST( !fs::exists( file_ph ) );
|
||||
create_file( file_ph, "" );
|
||||
BOOST_TEST( fs::exists( file_ph ) );
|
||||
BOOST_TEST( !fs::is_directory( file_ph ) );
|
||||
fs::remove( file_ph );
|
||||
BOOST_TEST( fs::remove( file_ph ) );
|
||||
BOOST_TEST( !fs::exists( file_ph ) );
|
||||
fs::remove( "no-such-file" ); // should be harmless
|
||||
fs::remove( "no-such-directory/no-such-file" ); // ditto
|
||||
BOOST_TEST( !fs::remove( "no-such-file" ) );
|
||||
BOOST_TEST( !fs::remove( "no-such-directory/no-such-file" ) );
|
||||
|
||||
// remove test on directory
|
||||
d1 = dir << "shortlife_dir";
|
||||
d1 = dir / "shortlife_dir";
|
||||
BOOST_TEST( !fs::exists( d1 ) );
|
||||
fs::create_directory( d1 );
|
||||
BOOST_TEST( fs::exists( d1 ) );
|
||||
BOOST_TEST( fs::is_directory( d1 ) );
|
||||
BOOST_TEST( fs::_is_empty( d1 ) );
|
||||
BOOST_TEST( throws_fs_error( bind( fs::remove, dir ) ) );
|
||||
fs::remove( d1 );
|
||||
BOOST_TEST( throws_fs_error( bind( fs::remove, dir ), fs::not_empty_error ) );
|
||||
BOOST_TEST( fs::remove( d1 ) );
|
||||
BOOST_TEST( !fs::exists( d1 ) );
|
||||
|
||||
// post-test cleanup
|
||||
|
@ -21,20 +21,21 @@ using boost::filesystem::path;
|
||||
using boost::next;
|
||||
using boost::prior;
|
||||
|
||||
#define BOOST_INCLUDE_MAIN
|
||||
#include <boost/test/test_tools.hpp>
|
||||
#include <boost/test/minimal.hpp>
|
||||
|
||||
#define PATH_CHECK( a, b ) check( a, b, __LINE__ )
|
||||
|
||||
namespace {
|
||||
int errors;
|
||||
|
||||
void check( const fs::path & source,
|
||||
const std::string & expected )
|
||||
const std::string & expected, int line )
|
||||
{
|
||||
if ( source.generic_path()== expected ) return;
|
||||
if ( source.string()== expected ) return;
|
||||
|
||||
++errors;
|
||||
|
||||
std::cout << "source.generic_path(): \"" << source.generic_path()
|
||||
std::cout << '(' << line << ") source.string(): \"" << source.string()
|
||||
<< "\" != expected: \"" << expected
|
||||
<< "\"" << std::endl;
|
||||
}
|
||||
@ -58,97 +59,110 @@ namespace {
|
||||
|
||||
int test_main( int, char*[] )
|
||||
{
|
||||
boost::function_requires< boost::ForwardIteratorConcept< fs::path::iterator > >();
|
||||
|
||||
path p1( "fe/fi/fo/fum" );
|
||||
path p2( p1 );
|
||||
path p3;
|
||||
BOOST_TEST( p1.string() != p3.string() );
|
||||
p3 = p2;
|
||||
|
||||
// p1.branch() = p2; // should fail
|
||||
// p1.branch_path() = p2; // should fail
|
||||
// *p1.begin() = ""; // should fail
|
||||
|
||||
// These verify various overloads don't cause compiler errors
|
||||
fs::exists( "foo" );
|
||||
fs::exists( std::string( "foo" ) );
|
||||
fs::exists( p1 );
|
||||
fs::exists( "foo" << p1 );
|
||||
fs::exists( std::string( "foo" ) << p1 );
|
||||
fs::exists( "foo" / p1 );
|
||||
fs::exists( std::string( "foo" ) / p1 );
|
||||
fs::exists( fs::check_posix_leaf( "foo" ) );
|
||||
|
||||
BOOST_TEST( p1.generic_path() == p2.generic_path() );
|
||||
BOOST_TEST( p1.generic_path() == p3.generic_path() );
|
||||
BOOST_TEST( p1.string() == p2.string() );
|
||||
BOOST_TEST( p1.string() == p3.string() );
|
||||
BOOST_TEST( path( "foo" ).leaf() == "foo" );
|
||||
BOOST_TEST( path( "foo" ).branch().generic_path() == "" );
|
||||
BOOST_TEST( path( "foo" ).branch_path().string() == "" );
|
||||
BOOST_TEST( p1.leaf() == "fum" );
|
||||
BOOST_TEST( p1.branch().generic_path() == "fe/fi/fo" );
|
||||
BOOST_TEST( path( "" ).is_null() == true );
|
||||
BOOST_TEST( path( "foo" ).is_null() == false );
|
||||
BOOST_TEST( p1.branch_path().string() == "fe/fi/fo" );
|
||||
BOOST_TEST( path( "" ).empty() == true );
|
||||
BOOST_TEST( path( "foo" ).empty() == false );
|
||||
|
||||
check( "", "" );
|
||||
PATH_CHECK( "", "" );
|
||||
|
||||
check( "foo", "foo" );
|
||||
check( path("") << "foo", "foo" );
|
||||
check( path("foo") << "", "foo" );
|
||||
PATH_CHECK( "foo", "foo" );
|
||||
PATH_CHECK( path("") / "foo", "foo" );
|
||||
PATH_CHECK( path("foo") / "", "foo" );
|
||||
PATH_CHECK( path( "/" ), "/" );
|
||||
PATH_CHECK( path( "/" ) / "", "/" );
|
||||
PATH_CHECK( path( "/f" ), "/f" );
|
||||
|
||||
check( "foo/bar", "foo/bar" );
|
||||
check( path("foo") << "bar", "foo/bar" );
|
||||
check( path("foo") << path("bar"), "foo/bar" );
|
||||
check( "foo" << path("bar"), "foo/bar" );
|
||||
PATH_CHECK( "/foo", "/foo" );
|
||||
PATH_CHECK( path("") / "/foo", "/foo" );
|
||||
PATH_CHECK( path("/foo") / "", "/foo" );
|
||||
|
||||
check( "a/b", "a/b" ); // probe for length effects
|
||||
check( path("a") << "b", "a/b" );
|
||||
PATH_CHECK( "foo/", "foo" );
|
||||
PATH_CHECK( path("") / "foo/", "foo" );
|
||||
PATH_CHECK( path("foo") / "/", "foo" );
|
||||
|
||||
check( "..", ".." );
|
||||
check( path("..") << "", ".." );
|
||||
check( path("") << "..", ".." );
|
||||
PATH_CHECK( "foo/bar", "foo/bar" );
|
||||
PATH_CHECK( path("foo") / "bar", "foo/bar" );
|
||||
PATH_CHECK( path("foo") / path("bar"), "foo/bar" );
|
||||
PATH_CHECK( "foo" / path("bar"), "foo/bar" );
|
||||
|
||||
check( "../..", "../.." );
|
||||
check( path("..") << ".." , "../.." );
|
||||
PATH_CHECK( "a/b", "a/b" ); // probe for length effects
|
||||
PATH_CHECK( path("a") / "b", "a/b" );
|
||||
|
||||
check( "../foo", "../foo" );
|
||||
check( path("..") << "foo" , "../foo" );
|
||||
PATH_CHECK( "..", ".." );
|
||||
PATH_CHECK( path("..") / "", ".." );
|
||||
PATH_CHECK( path("") / "..", ".." );
|
||||
|
||||
check( "foo/..", "" );
|
||||
check( path("foo") << ".." , "" );
|
||||
PATH_CHECK( "../..", "../.." );
|
||||
PATH_CHECK( path("..") / ".." , "../.." );
|
||||
|
||||
check( "../f", "../f" );
|
||||
check( path("..") << "f" , "../f" );
|
||||
PATH_CHECK( "../foo", "../foo" );
|
||||
PATH_CHECK( path("..") / "foo" , "../foo" );
|
||||
|
||||
check( "f/..", "" );
|
||||
check( path("f") << ".." , "" );
|
||||
PATH_CHECK( "foo/..", "" );
|
||||
PATH_CHECK( path("foo") / ".." , "" );
|
||||
|
||||
check( "foo/../..", ".." );
|
||||
check( path("foo") << ".." << ".." , ".." );
|
||||
PATH_CHECK( "../f", "../f" );
|
||||
PATH_CHECK( path("..") / "f" , "../f" );
|
||||
|
||||
check( "foo/../../..", "../.." );
|
||||
check( path("foo") << ".." << ".." << ".." , "../.." );
|
||||
PATH_CHECK( "f/..", "" );
|
||||
PATH_CHECK( path("f") / ".." , "" );
|
||||
|
||||
check( "foo/../bar", "bar" );
|
||||
check( path("foo") << ".." << "bar" , "bar" );
|
||||
PATH_CHECK( "foo/../..", ".." );
|
||||
PATH_CHECK( path("foo") / ".." / ".." , ".." );
|
||||
|
||||
check( "foo/bar/..", "foo" );
|
||||
check( path("foo") << "bar" << ".." , "foo" );
|
||||
PATH_CHECK( "foo/../../..", "../.." );
|
||||
PATH_CHECK( path("foo") / ".." / ".." / ".." , "../.." );
|
||||
|
||||
check( "foo/bar/../..", "" );
|
||||
check( path("foo") << "bar" << ".." << "..", "" );
|
||||
PATH_CHECK( "foo/../bar", "bar" );
|
||||
PATH_CHECK( path("foo") / ".." / "bar" , "bar" );
|
||||
|
||||
check( "foo/bar/../blah", "foo/blah" );
|
||||
check( path("foo") << "bar" << ".." << "blah", "foo/blah" );
|
||||
PATH_CHECK( "foo/bar/..", "foo" );
|
||||
PATH_CHECK( path("foo") / "bar" / ".." , "foo" );
|
||||
|
||||
check( "f/../b", "b" );
|
||||
check( path("f") << ".." << "b" , "b" );
|
||||
PATH_CHECK( "foo/bar/../..", "" );
|
||||
PATH_CHECK( path("foo") / "bar" / ".." / "..", "" );
|
||||
|
||||
check( "f/b/..", "f" );
|
||||
check( path("f") << "b" << ".." , "f" );
|
||||
PATH_CHECK( "foo/bar/../blah", "foo/blah" );
|
||||
PATH_CHECK( path("foo") / "bar" / ".." / "blah", "foo/blah" );
|
||||
|
||||
check( "f/b/../a", "f/a" );
|
||||
check( path("f") << "b" << ".." << "a", "f/a" );
|
||||
PATH_CHECK( "f/../b", "b" );
|
||||
PATH_CHECK( path("f") / ".." / "b" , "b" );
|
||||
|
||||
check( "foo/bar/blah/../..", "foo" );
|
||||
check( path("foo") << "bar" << "blah" << ".." << "..", "foo" );
|
||||
PATH_CHECK( "f/b/..", "f" );
|
||||
PATH_CHECK( path("f") / "b" / ".." , "f" );
|
||||
|
||||
check( "foo/bar/blah/../../bletch", "foo/bletch" );
|
||||
check( path("foo") << "bar" << "blah" << ".." << ".." << "bletch", "foo/bletch" );
|
||||
PATH_CHECK( "f/b/../a", "f/a" );
|
||||
PATH_CHECK( path("f") / "b" / ".." / "a", "f/a" );
|
||||
|
||||
PATH_CHECK( "foo/bar/blah/../..", "foo" );
|
||||
PATH_CHECK( path("foo") / "bar" / "blah" / ".." / "..", "foo" );
|
||||
|
||||
PATH_CHECK( "foo/bar/blah/../../bletch", "foo/bletch" );
|
||||
PATH_CHECK( path("foo") / "bar" / "blah" / ".." / ".." / "bletch", "foo/bletch" );
|
||||
|
||||
BOOST_TEST( fs::posix_name("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.-_") );
|
||||
BOOST_TEST( !fs::posix_name("F$O") );
|
||||
@ -167,10 +181,7 @@ int test_main( int, char*[] )
|
||||
BOOST_TEST( !fs::boost_directory_name("12345678901234567890123456789012") );
|
||||
BOOST_TEST( !fs::boost_directory_name("F$O") );
|
||||
|
||||
check_throw( "/" );
|
||||
check_throw( "...." );
|
||||
check_throw( "/foo" );
|
||||
check_throw( "foo/" );
|
||||
check_throw( "foo/...." );
|
||||
check_throw( "foo//bar" );
|
||||
check_throw( "foo\\bar" );
|
||||
@ -189,9 +200,8 @@ int test_main( int, char*[] )
|
||||
check_throw( "//share" );
|
||||
check_throw( "prn:" );
|
||||
|
||||
path itr_ck( "/foo/bar", fs::system_specific );
|
||||
path itr_ck( "/foo/bar" );
|
||||
path::iterator itr( itr_ck.begin() );
|
||||
//std::cout << "\"" << *itr << "\"" << std::endl;
|
||||
BOOST_TEST( *itr == std::string( "/" ) );
|
||||
BOOST_TEST( *++itr == std::string( "foo" ) );
|
||||
BOOST_TEST( *++itr == std::string( "bar" ) );
|
||||
@ -203,13 +213,13 @@ int test_main( int, char*[] )
|
||||
itr_ck = "";
|
||||
BOOST_TEST( itr_ck.begin() == itr_ck.end() );
|
||||
|
||||
itr_ck = path( "/", fs::system_specific );
|
||||
itr_ck = path( "/" );
|
||||
BOOST_TEST( *itr_ck.begin() == std::string( "/" ) );
|
||||
BOOST_TEST( next(itr_ck.begin()) == itr_ck.end() );
|
||||
BOOST_TEST( *prior(itr_ck.end()) == std::string( "/" ) );
|
||||
BOOST_TEST( prior(itr_ck.end()) == itr_ck.begin() );
|
||||
|
||||
itr_ck = path( "/foo", fs::system_specific );
|
||||
itr_ck = path( "/foo" );
|
||||
BOOST_TEST( *itr_ck.begin() == std::string( "/" ) );
|
||||
BOOST_TEST( *next( itr_ck.begin() ) == std::string( "foo" ) );
|
||||
BOOST_TEST( next(next( itr_ck.begin() )) == itr_ck.end() );
|
||||
@ -224,21 +234,256 @@ int test_main( int, char*[] )
|
||||
BOOST_TEST( *prior( itr_ck.end() ) == std::string( "foo" ) );
|
||||
BOOST_TEST( prior( itr_ck.end() ) == itr_ck.begin() );
|
||||
|
||||
path p;
|
||||
|
||||
p = "";
|
||||
BOOST_TEST( p.relative_path().string() == "" );
|
||||
BOOST_TEST( p.branch_path().string() == "" );
|
||||
BOOST_TEST( p.leaf() == "" );
|
||||
BOOST_TEST( p.root_name() == "" );
|
||||
BOOST_TEST( p.root_directory() == "" );
|
||||
BOOST_TEST( p.root_path().string() == "" );
|
||||
BOOST_TEST( !p.has_root_path() );
|
||||
BOOST_TEST( !p.has_root_name() );
|
||||
BOOST_TEST( !p.has_root_directory() );
|
||||
BOOST_TEST( !p.has_relative_path() );
|
||||
BOOST_TEST( !p.has_leaf() );
|
||||
BOOST_TEST( !p.has_branch_path() );
|
||||
BOOST_TEST( !p.is_complete() );
|
||||
|
||||
p = "/";
|
||||
BOOST_TEST( p.relative_path().string() == "" );
|
||||
BOOST_TEST( p.branch_path().string() == "" );
|
||||
BOOST_TEST( p.leaf() == "/" );
|
||||
BOOST_TEST( p.root_name() == "" );
|
||||
BOOST_TEST( p.root_directory() == "/" );
|
||||
BOOST_TEST( p.root_path().string() == "/" );
|
||||
BOOST_TEST( p.has_root_path() );
|
||||
BOOST_TEST( !p.has_root_name() );
|
||||
BOOST_TEST( p.has_root_directory() );
|
||||
BOOST_TEST( !p.has_relative_path() );
|
||||
BOOST_TEST( p.has_leaf() );
|
||||
BOOST_TEST( !p.has_branch_path() );
|
||||
BOOST_TEST( fs::detail::single_root_name() == p.is_complete() );
|
||||
|
||||
p = "foo";
|
||||
BOOST_TEST( p.relative_path().string() == "foo" );
|
||||
BOOST_TEST( p.branch_path().string() == "" );
|
||||
BOOST_TEST( p.leaf() == "foo" );
|
||||
BOOST_TEST( p.root_name() == "" );
|
||||
BOOST_TEST( p.root_directory() == "" );
|
||||
BOOST_TEST( p.root_path().string() == "" );
|
||||
BOOST_TEST( !p.has_root_path() );
|
||||
BOOST_TEST( !p.has_root_name() );
|
||||
BOOST_TEST( !p.has_root_directory() );
|
||||
BOOST_TEST( p.has_relative_path() );
|
||||
BOOST_TEST( p.has_leaf() );
|
||||
BOOST_TEST( !p.has_branch_path() );
|
||||
BOOST_TEST( !p.is_complete() );
|
||||
|
||||
p = "/foo";
|
||||
BOOST_TEST( p.relative_path().string() == "foo" );
|
||||
BOOST_TEST( p.branch_path().string() == "/" );
|
||||
BOOST_TEST( p.leaf() == "foo" );
|
||||
BOOST_TEST( p.root_name() == "" );
|
||||
BOOST_TEST( p.root_directory() == "/" );
|
||||
BOOST_TEST( p.root_path().string() == "/" );
|
||||
BOOST_TEST( p.has_root_path() );
|
||||
BOOST_TEST( !p.has_root_name() );
|
||||
BOOST_TEST( p.has_root_directory() );
|
||||
BOOST_TEST( p.has_relative_path() );
|
||||
BOOST_TEST( p.has_leaf() );
|
||||
BOOST_TEST( p.has_branch_path() );
|
||||
BOOST_TEST( fs::detail::single_root_name() == p.is_complete() );
|
||||
|
||||
p = "foo/bar";
|
||||
BOOST_TEST( p.relative_path().string() == "foo/bar" );
|
||||
BOOST_TEST( p.branch_path().string() == "foo" );
|
||||
BOOST_TEST( p.leaf() == "bar" );
|
||||
BOOST_TEST( p.root_name() == "" );
|
||||
BOOST_TEST( p.root_directory() == "" );
|
||||
BOOST_TEST( p.root_path().string() == "" );
|
||||
BOOST_TEST( !p.has_root_path() );
|
||||
BOOST_TEST( !p.has_root_name() );
|
||||
BOOST_TEST( !p.has_root_directory() );
|
||||
BOOST_TEST( p.has_relative_path() );
|
||||
BOOST_TEST( p.has_leaf() );
|
||||
BOOST_TEST( p.has_branch_path() );
|
||||
BOOST_TEST( !p.is_complete() );
|
||||
|
||||
p = "/foo/bar";
|
||||
BOOST_TEST( p.relative_path().string() == "foo/bar" );
|
||||
BOOST_TEST( p.branch_path().string() == "/foo" );
|
||||
BOOST_TEST( p.leaf() == "bar" );
|
||||
BOOST_TEST( p.root_name() == "" );
|
||||
BOOST_TEST( p.root_directory() == "/" );
|
||||
BOOST_TEST( p.root_path().string() == "/" );
|
||||
BOOST_TEST( p.has_root_path() );
|
||||
BOOST_TEST( !p.has_root_name() );
|
||||
BOOST_TEST( p.has_root_directory() );
|
||||
BOOST_TEST( p.has_relative_path() );
|
||||
BOOST_TEST( p.has_leaf() );
|
||||
BOOST_TEST( p.has_branch_path() );
|
||||
BOOST_TEST( fs::detail::single_root_name() == p.is_complete() );
|
||||
|
||||
if ( std::strcmp( fs::detail::implementation_name(), "Windows" ) == 0 )
|
||||
{
|
||||
itr_ck = path( "c:", fs::system_specific );
|
||||
PATH_CHECK( path( "\\", fs::native ), "/" );
|
||||
PATH_CHECK( path( "\\f", fs::native ), "/f" );
|
||||
PATH_CHECK( path( "\\foo", fs::native ), "/foo" );
|
||||
PATH_CHECK( path( "foo\\bar", fs::native ), "foo/bar" );
|
||||
PATH_CHECK( path( "foo bar", fs::native ), "foo bar" );
|
||||
PATH_CHECK( path( "c:", fs::native ), "c:" );
|
||||
PATH_CHECK( path( "c:/", fs::native ), "c:/" );
|
||||
PATH_CHECK( path( "c:foo", fs::native ), "c:foo" );
|
||||
PATH_CHECK( path( "c:/foo", fs::native ), "c:/foo" );
|
||||
PATH_CHECK( path( "//share", fs::native ), "//share" );
|
||||
PATH_CHECK( path( "//share/", fs::native ), "//share/" );
|
||||
PATH_CHECK( path( "//share/foo", fs::native ), "//share/foo" );
|
||||
PATH_CHECK( path( "\\\\share", fs::native ), "//share" );
|
||||
PATH_CHECK( path( "\\\\share\\", fs::native ), "//share/" );
|
||||
PATH_CHECK( path( "\\\\share\\foo", fs::native ), "//share/foo" );
|
||||
PATH_CHECK( path( "c:/foo", fs::native ), "c:/foo" );
|
||||
PATH_CHECK( path( "prn:", fs::native ), "prn:" );
|
||||
|
||||
p = path( "c:", fs::native );
|
||||
BOOST_TEST( p.relative_path().string() == "" );
|
||||
BOOST_TEST( p.branch_path().string() == "" );
|
||||
BOOST_TEST( p.leaf() == "c:" );
|
||||
BOOST_TEST( p.root_name() == "c:" );
|
||||
BOOST_TEST( p.root_directory() == "" );
|
||||
BOOST_TEST( p.root_path().string() == "c:" );
|
||||
BOOST_TEST( p.has_root_path() );
|
||||
BOOST_TEST( p.has_root_name() );
|
||||
BOOST_TEST( !p.has_root_directory() );
|
||||
BOOST_TEST( !p.has_relative_path() );
|
||||
BOOST_TEST( p.has_leaf() );
|
||||
BOOST_TEST( !p.has_branch_path() );
|
||||
BOOST_TEST( !p.is_complete() );
|
||||
|
||||
p = path( "c:foo", fs::native );
|
||||
BOOST_TEST( p.relative_path().string() == "foo" );
|
||||
BOOST_TEST( p.branch_path().string() == "c:" );
|
||||
BOOST_TEST( p.leaf() == "foo" );
|
||||
BOOST_TEST( p.root_name() == "c:" );
|
||||
BOOST_TEST( p.root_directory() == "" );
|
||||
BOOST_TEST( p.root_path().string() == "c:" );
|
||||
BOOST_TEST( p.has_root_path() );
|
||||
BOOST_TEST( p.has_root_name() );
|
||||
BOOST_TEST( !p.has_root_directory() );
|
||||
BOOST_TEST( p.has_relative_path() );
|
||||
BOOST_TEST( p.has_leaf() );
|
||||
BOOST_TEST( p.has_branch_path() );
|
||||
BOOST_TEST( !p.is_complete() );
|
||||
|
||||
p = path( "c:/", fs::native );
|
||||
BOOST_TEST( p.relative_path().string() == "" );
|
||||
BOOST_TEST( p.branch_path().string() == "c:" );
|
||||
BOOST_TEST( p.leaf() == "/" );
|
||||
BOOST_TEST( p.root_name() == "c:" );
|
||||
BOOST_TEST( p.root_directory() == "/" );
|
||||
BOOST_TEST( p.root_path().string() == "c:/" );
|
||||
BOOST_TEST( p.has_root_path() );
|
||||
BOOST_TEST( p.has_root_name() );
|
||||
BOOST_TEST( p.has_root_directory() );
|
||||
BOOST_TEST( !p.has_relative_path() );
|
||||
BOOST_TEST( p.has_leaf() );
|
||||
BOOST_TEST( p.has_branch_path() );
|
||||
BOOST_TEST( p.is_complete() );
|
||||
|
||||
p = path( "c:/foo", fs::native );
|
||||
BOOST_TEST( p.relative_path().string() == "foo" );
|
||||
BOOST_TEST( p.branch_path().string() == "c:/" );
|
||||
BOOST_TEST( p.leaf() == "foo" );
|
||||
BOOST_TEST( p.root_name() == "c:" );
|
||||
BOOST_TEST( p.root_directory() == "/" );
|
||||
BOOST_TEST( p.root_path().string() == "c:/" );
|
||||
BOOST_TEST( p.has_root_path() );
|
||||
BOOST_TEST( p.has_root_name() );
|
||||
BOOST_TEST( p.has_root_directory() );
|
||||
BOOST_TEST( p.has_relative_path() );
|
||||
BOOST_TEST( p.has_leaf() );
|
||||
BOOST_TEST( p.has_branch_path() );
|
||||
BOOST_TEST( p.is_complete() );
|
||||
|
||||
/* Commented out until the semantics of //share are clearer.
|
||||
|
||||
p = path( "//share", fs::native );
|
||||
BOOST_TEST( p.string() == "//share" );
|
||||
BOOST_TEST( p.relative_path().string() == "" );
|
||||
BOOST_TEST( p.branch_path().string() == "" );
|
||||
BOOST_TEST( p.leaf() == "//share" );
|
||||
BOOST_TEST( p.root_name() == "//share" );
|
||||
BOOST_TEST( p.root_directory() == "/" );
|
||||
BOOST_TEST( p.root_path().string() == "//share/" );
|
||||
BOOST_TEST( p.has_root_path() );
|
||||
BOOST_TEST( p.has_root_name() );
|
||||
BOOST_TEST( !p.has_root_directory() );
|
||||
BOOST_TEST( !p.has_relative_path() );
|
||||
BOOST_TEST( p.has_leaf() );
|
||||
BOOST_TEST( !p.has_branch_path() );
|
||||
BOOST_TEST( !p.is_complete() );
|
||||
*/
|
||||
p = path( "//share/", fs::native );
|
||||
BOOST_TEST( p.relative_path().string() == "" );
|
||||
BOOST_TEST( p.branch_path().string() == "//share" );
|
||||
BOOST_TEST( p.leaf() == "/" );
|
||||
BOOST_TEST( p.root_name() == "//share" );
|
||||
BOOST_TEST( p.root_directory() == "/" );
|
||||
BOOST_TEST( p.root_path().string() == "//share/" );
|
||||
BOOST_TEST( p.has_root_path() );
|
||||
BOOST_TEST( p.has_root_name() );
|
||||
BOOST_TEST( p.has_root_directory() );
|
||||
BOOST_TEST( !p.has_relative_path() );
|
||||
BOOST_TEST( p.has_leaf() );
|
||||
BOOST_TEST( p.has_branch_path() );
|
||||
BOOST_TEST( p.is_complete() );
|
||||
|
||||
p = path( "//share/foo", fs::native );
|
||||
BOOST_TEST( p.relative_path().string() == "foo" );
|
||||
BOOST_TEST( p.branch_path().string() == "//share/" );
|
||||
BOOST_TEST( p.leaf() == "foo" );
|
||||
BOOST_TEST( p.root_name() == "//share" );
|
||||
BOOST_TEST( p.root_directory() == "/" );
|
||||
BOOST_TEST( p.root_path().string() == "//share/" );
|
||||
BOOST_TEST( p.has_root_path() );
|
||||
BOOST_TEST( p.has_root_name() );
|
||||
BOOST_TEST( p.has_root_directory() );
|
||||
BOOST_TEST( p.has_relative_path() );
|
||||
BOOST_TEST( p.has_leaf() );
|
||||
BOOST_TEST( p.has_branch_path() );
|
||||
BOOST_TEST( p.is_complete() );
|
||||
|
||||
p = path( "prn:", fs::native );
|
||||
BOOST_TEST( p.relative_path().string() == "" );
|
||||
BOOST_TEST( p.branch_path().string() == "" );
|
||||
BOOST_TEST( p.leaf() == "prn:" );
|
||||
BOOST_TEST( p.root_name() == "prn:" );
|
||||
BOOST_TEST( p.root_directory() == "" );
|
||||
BOOST_TEST( p.root_path().string() == "prn:" );
|
||||
BOOST_TEST( p.has_root_path() );
|
||||
BOOST_TEST( p.has_root_name() );
|
||||
BOOST_TEST( !p.has_root_directory() );
|
||||
BOOST_TEST( !p.has_relative_path() );
|
||||
BOOST_TEST( p.has_leaf() );
|
||||
BOOST_TEST( !p.has_branch_path() );
|
||||
BOOST_TEST( p.is_complete() );
|
||||
|
||||
itr_ck = path( "c:", fs::native );
|
||||
BOOST_TEST( *itr_ck.begin() == std::string( "c:" ) );
|
||||
BOOST_TEST( next( itr_ck.begin() ) == itr_ck.end() );
|
||||
BOOST_TEST( prior( itr_ck.end() ) == itr_ck.begin() );
|
||||
BOOST_TEST( *prior( itr_ck.end() ) == std::string( "c:" ) );
|
||||
|
||||
itr_ck = path( "c:/", fs::system_specific );
|
||||
BOOST_TEST( *itr_ck.begin() == std::string( "c:/" ) );
|
||||
BOOST_TEST( next( itr_ck.begin() ) == itr_ck.end() );
|
||||
BOOST_TEST( prior( itr_ck.end() ) == itr_ck.begin() );
|
||||
BOOST_TEST( *prior( itr_ck.end() ) == std::string( "c:/" ) );
|
||||
itr_ck = path( "c:/", fs::native );
|
||||
BOOST_TEST( *itr_ck.begin() == std::string( "c:" ) );
|
||||
BOOST_TEST( *next( itr_ck.begin() ) == std::string( "/" ) );
|
||||
BOOST_TEST( next( next( itr_ck.begin() )) == itr_ck.end() );
|
||||
BOOST_TEST( prior( prior( itr_ck.end() )) == itr_ck.begin() );
|
||||
BOOST_TEST( *prior( itr_ck.end() ) == std::string( "/" ) );
|
||||
BOOST_TEST( *prior( prior( itr_ck.end() )) == std::string( "c:" ) );
|
||||
|
||||
itr_ck = path( "c:foo", fs::system_specific );
|
||||
itr_ck = path( "c:foo", fs::native );
|
||||
BOOST_TEST( *itr_ck.begin() == std::string( "c:" ) );
|
||||
BOOST_TEST( *next( itr_ck.begin() ) == std::string( "foo" ) );
|
||||
BOOST_TEST( next(next( itr_ck.begin() )) == itr_ck.end() );
|
||||
@ -246,68 +491,45 @@ int test_main( int, char*[] )
|
||||
BOOST_TEST( *prior( itr_ck.end() ) == std::string( "foo" ) );
|
||||
BOOST_TEST( *prior(prior( itr_ck.end() )) == std::string( "c:" ) );
|
||||
|
||||
itr_ck = path( "c:/foo", fs::system_specific );
|
||||
BOOST_TEST( *itr_ck.begin() == std::string( "c:/" ) );
|
||||
BOOST_TEST( *next( itr_ck.begin() ) == std::string( "foo" ) );
|
||||
BOOST_TEST( next(next( itr_ck.begin() )) == itr_ck.end() );
|
||||
BOOST_TEST( prior(prior( itr_ck.end() )) == itr_ck.begin() );
|
||||
itr_ck = path( "c:/foo", fs::native );
|
||||
BOOST_TEST( *itr_ck.begin() == std::string( "c:" ) );
|
||||
BOOST_TEST( *next( itr_ck.begin() ) == std::string( "/" ) );
|
||||
BOOST_TEST( *next( next( itr_ck.begin() )) == std::string( "foo" ) );
|
||||
BOOST_TEST( next( next( next( itr_ck.begin() ))) == itr_ck.end() );
|
||||
BOOST_TEST( prior( prior( prior( itr_ck.end() ))) == itr_ck.begin() );
|
||||
BOOST_TEST( *prior( itr_ck.end() ) == std::string( "foo" ) );
|
||||
BOOST_TEST( *prior(prior( itr_ck.end() )) == std::string( "c:/" ) );
|
||||
BOOST_TEST( *prior( prior( itr_ck.end() )) == std::string( "/" ) );
|
||||
BOOST_TEST( *prior( prior( prior( itr_ck.end() ))) == std::string( "c:" ) );
|
||||
|
||||
itr_ck = path( "//share", fs::system_specific );
|
||||
itr_ck = path( "//share", fs::native );
|
||||
BOOST_TEST( *itr_ck.begin() == std::string( "//share" ) );
|
||||
BOOST_TEST( next( itr_ck.begin() ) == itr_ck.end() );
|
||||
BOOST_TEST( prior( itr_ck.end() ) == itr_ck.begin() );
|
||||
BOOST_TEST( *prior( itr_ck.end() ) == std::string( "//share" ) );
|
||||
|
||||
itr_ck = path( "//share/foo", fs::system_specific );
|
||||
itr_ck = path( "//share/", fs::native );
|
||||
BOOST_TEST( *itr_ck.begin() == std::string( "//share" ) );
|
||||
BOOST_TEST( *next( itr_ck.begin() ) == std::string( "foo" ) );
|
||||
BOOST_TEST( *next( itr_ck.begin() ) == std::string( "/" ) );
|
||||
BOOST_TEST( next(next( itr_ck.begin() )) == itr_ck.end() );
|
||||
BOOST_TEST( prior(prior( itr_ck.end() )) == itr_ck.begin() );
|
||||
BOOST_TEST( *prior( itr_ck.end() ) == std::string( "foo" ) );
|
||||
BOOST_TEST( *prior( itr_ck.end() ) == std::string( "/" ) );
|
||||
BOOST_TEST( *prior(prior( itr_ck.end() )) == std::string( "//share" ) );
|
||||
|
||||
itr_ck = path( "prn:", fs::system_specific );
|
||||
itr_ck = path( "//share/foo", fs::native );
|
||||
BOOST_TEST( *itr_ck.begin() == std::string( "//share" ) );
|
||||
BOOST_TEST( *next( itr_ck.begin() ) == std::string( "/" ) );
|
||||
BOOST_TEST( *next(next( itr_ck.begin() )) == std::string( "foo" ) );
|
||||
BOOST_TEST( next(next(next( itr_ck.begin() ))) == itr_ck.end() );
|
||||
BOOST_TEST( prior(prior(prior( itr_ck.end() ))) == itr_ck.begin() );
|
||||
BOOST_TEST( *prior( itr_ck.end() ) == std::string( "foo" ) );
|
||||
BOOST_TEST( *prior(prior( itr_ck.end() )) == std::string( "/" ) );
|
||||
BOOST_TEST( *prior(prior(prior( itr_ck.end() ))) == std::string( "//share" ) );
|
||||
|
||||
itr_ck = path( "prn:", fs::native );
|
||||
BOOST_TEST( *itr_ck.begin() == std::string( "prn:" ) );
|
||||
BOOST_TEST( next( itr_ck.begin() ) == itr_ck.end() );
|
||||
BOOST_TEST( prior( itr_ck.end() ) == itr_ck.begin() );
|
||||
BOOST_TEST( *prior( itr_ck.end() ) == std::string( "prn:" ) );
|
||||
|
||||
check( path( "/", fs::system_specific ), "/" );
|
||||
check( path( "/f", fs::system_specific ), "/f" );
|
||||
check( path( "/foo", fs::system_specific ), "/foo" );
|
||||
check( path( "\\", fs::system_specific ), "/" );
|
||||
check( path( "\\f", fs::system_specific ), "/f" );
|
||||
check( path( "\\foo", fs::system_specific ), "/foo" );
|
||||
check( path( "foo\\bar", fs::system_specific ), "foo/bar" );
|
||||
check( path( "foo bar", fs::system_specific ), "foo bar" );
|
||||
check( path( "c:", fs::system_specific ), "c:" );
|
||||
check( path( "c:/", fs::system_specific ), "c:/" );
|
||||
check( path( "c:foo", fs::system_specific ), "c:foo" );
|
||||
check( path( "c:/foo", fs::system_specific ), "c:/foo" );
|
||||
check( path( "//share", fs::system_specific ), "//share" );
|
||||
check( path( "//share/foo", fs::system_specific ), "//share/foo" );
|
||||
check( path( "\\\\share", fs::system_specific ), "//share" );
|
||||
check( path( "\\\\share\\foo", fs::system_specific ), "//share/foo" );
|
||||
check( path( "c:/foo", fs::system_specific ), "c:/foo" );
|
||||
check( path( "prn:", fs::system_specific ), "prn:" );
|
||||
|
||||
BOOST_TEST( path( "/", fs::system_specific ).leaf() == "/" );
|
||||
BOOST_TEST( path( "c:", fs::system_specific ).leaf() == "c:" );
|
||||
BOOST_TEST( path( "c:/", fs::system_specific ).leaf() == "c:/" );
|
||||
BOOST_TEST( path( "c:foo", fs::system_specific ).leaf() == "foo" );
|
||||
BOOST_TEST( path( "c:/foo", fs::system_specific ).leaf() == "foo" );
|
||||
BOOST_TEST( path( "//share", fs::system_specific ).leaf() == "//share" );
|
||||
BOOST_TEST( path( "//share/foo", fs::system_specific ).leaf() == "foo" );
|
||||
|
||||
BOOST_TEST( path( "/", fs::system_specific ).branch().generic_path() == "" );
|
||||
BOOST_TEST( path( "c:", fs::system_specific ).branch().generic_path() == "" );
|
||||
BOOST_TEST( path( "c:/", fs::system_specific ).branch().generic_path() == "" );
|
||||
BOOST_TEST( path( "c:foo", fs::system_specific ).branch().generic_path() == "c:" );
|
||||
BOOST_TEST( path( "c:/foo", fs::system_specific ).branch().generic_path() == "c:/" );
|
||||
BOOST_TEST( path( "//share", fs::system_specific ).branch().generic_path() == "" );
|
||||
BOOST_TEST( path( "//share/foo", fs::system_specific ).branch().generic_path() == "//share" );
|
||||
}
|
||||
// std::cout << errors << " errors detected\n";
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user