mirror of
https://github.com/boostorg/filesystem.git
synced 2025-05-11 05:07:55 +00:00
initial commit - review comments not yet applied
[SVN r15831]
This commit is contained in:
commit
543669496a
96
.gitattributes
vendored
Normal file
96
.gitattributes
vendored
Normal file
@ -0,0 +1,96 @@
|
||||
* text=auto !eol svneol=native#text/plain
|
||||
*.gitattributes text svneol=native#text/plain
|
||||
|
||||
# Scriptish formats
|
||||
*.bat text svneol=native#text/plain
|
||||
*.bsh text svneol=native#text/x-beanshell
|
||||
*.cgi text svneol=native#text/plain
|
||||
*.cmd text svneol=native#text/plain
|
||||
*.js text svneol=native#text/javascript
|
||||
*.php text svneol=native#text/x-php
|
||||
*.pl text svneol=native#text/x-perl
|
||||
*.pm text svneol=native#text/x-perl
|
||||
*.py text svneol=native#text/x-python
|
||||
*.sh eol=lf svneol=LF#text/x-sh
|
||||
configure eol=lf svneol=LF#text/x-sh
|
||||
|
||||
# Image formats
|
||||
*.bmp binary svneol=unset#image/bmp
|
||||
*.gif binary svneol=unset#image/gif
|
||||
*.ico binary svneol=unset#image/ico
|
||||
*.jpeg binary svneol=unset#image/jpeg
|
||||
*.jpg binary svneol=unset#image/jpeg
|
||||
*.png binary svneol=unset#image/png
|
||||
*.tif binary svneol=unset#image/tiff
|
||||
*.tiff binary svneol=unset#image/tiff
|
||||
*.svg text svneol=native#image/svg%2Bxml
|
||||
|
||||
# Data formats
|
||||
*.pdf binary svneol=unset#application/pdf
|
||||
*.avi binary svneol=unset#video/avi
|
||||
*.doc binary svneol=unset#application/msword
|
||||
*.dsp text svneol=crlf#text/plain
|
||||
*.dsw text svneol=crlf#text/plain
|
||||
*.eps binary svneol=unset#application/postscript
|
||||
*.gz binary svneol=unset#application/gzip
|
||||
*.mov binary svneol=unset#video/quicktime
|
||||
*.mp3 binary svneol=unset#audio/mpeg
|
||||
*.ppt binary svneol=unset#application/vnd.ms-powerpoint
|
||||
*.ps binary svneol=unset#application/postscript
|
||||
*.psd binary svneol=unset#application/photoshop
|
||||
*.rdf binary svneol=unset#text/rdf
|
||||
*.rss text svneol=unset#text/xml
|
||||
*.rtf binary svneol=unset#text/rtf
|
||||
*.sln text svneol=native#text/plain
|
||||
*.swf binary svneol=unset#application/x-shockwave-flash
|
||||
*.tgz binary svneol=unset#application/gzip
|
||||
*.vcproj text svneol=native#text/xml
|
||||
*.vcxproj text svneol=native#text/xml
|
||||
*.vsprops text svneol=native#text/xml
|
||||
*.wav binary svneol=unset#audio/wav
|
||||
*.xls binary svneol=unset#application/vnd.ms-excel
|
||||
*.zip binary svneol=unset#application/zip
|
||||
|
||||
# Text formats
|
||||
.htaccess text svneol=native#text/plain
|
||||
*.bbk text svneol=native#text/xml
|
||||
*.cmake text svneol=native#text/plain
|
||||
*.css text svneol=native#text/css
|
||||
*.dtd text svneol=native#text/xml
|
||||
*.htm text svneol=native#text/html
|
||||
*.html text svneol=native#text/html
|
||||
*.ini text svneol=native#text/plain
|
||||
*.log text svneol=native#text/plain
|
||||
*.mak text svneol=native#text/plain
|
||||
*.qbk text svneol=native#text/plain
|
||||
*.rst text svneol=native#text/plain
|
||||
*.sql text svneol=native#text/x-sql
|
||||
*.txt text svneol=native#text/plain
|
||||
*.xhtml text svneol=native#text/xhtml%2Bxml
|
||||
*.xml text svneol=native#text/xml
|
||||
*.xsd text svneol=native#text/xml
|
||||
*.xsl text svneol=native#text/xml
|
||||
*.xslt text svneol=native#text/xml
|
||||
*.xul text svneol=native#text/xul
|
||||
*.yml text svneol=native#text/plain
|
||||
boost-no-inspect text svneol=native#text/plain
|
||||
CHANGES text svneol=native#text/plain
|
||||
COPYING text svneol=native#text/plain
|
||||
INSTALL text svneol=native#text/plain
|
||||
Jamfile text svneol=native#text/plain
|
||||
Jamroot text svneol=native#text/plain
|
||||
Jamfile.v2 text svneol=native#text/plain
|
||||
Jamrules text svneol=native#text/plain
|
||||
Makefile* text svneol=native#text/plain
|
||||
README text svneol=native#text/plain
|
||||
TODO text svneol=native#text/plain
|
||||
|
||||
# Code formats
|
||||
*.c text svneol=native#text/plain
|
||||
*.cpp text svneol=native#text/plain
|
||||
*.h text svneol=native#text/plain
|
||||
*.hpp text svneol=native#text/plain
|
||||
*.ipp text svneol=native#text/plain
|
||||
*.tpp text svneol=native#text/plain
|
||||
*.jam text svneol=native#text/plain
|
||||
*.java text svneol=native#text/plain
|
10
build/Jamfile
Normal file
10
build/Jamfile
Normal file
@ -0,0 +1,10 @@
|
||||
# Boost Filesystem Library Build Jamfile
|
||||
|
||||
subproject libs/filesystem/build ;
|
||||
|
||||
SOURCES = exception operations_posix_windows path_posix_windows ;
|
||||
|
||||
lib fs : ../src/$(SOURCES).cpp
|
||||
: <include>$(BOOST_ROOT) <sysinclude>$(BOOST_ROOT)
|
||||
: debug release
|
||||
;
|
291
doc/design.htm
Normal file
291
doc/design.htm
Normal file
@ -0,0 +1,291 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Language" content="en-us">
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<title>Boost Filesystem Library Design</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF">
|
||||
|
||||
<h1>
|
||||
<img border="0" src="../../../c++boost.gif" align="center" width="277" height="86">Filesystem
|
||||
Library Design</h1>
|
||||
|
||||
<p><a href="#Introduction">Introduction</a><br>
|
||||
<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="#References">References</a></p>
|
||||
|
||||
<h2><a name="Introduction">Introduction</a></h2>
|
||||
|
||||
<p>The primary motivation for beginning work on the Filesystem Library was
|
||||
frustration with Boost administrative tools. Scripts were written in
|
||||
Python, Perl, Bash, and Windows command languages. There was no single
|
||||
scripting language familiar and acceptable to all Boost administrators. Yet they
|
||||
were all skilled C++ programmers - why couldn't C++ be used as the scripting
|
||||
language?</p>
|
||||
|
||||
<p>The key feature C++ lacked for script-like applications was the ability to
|
||||
perform portable filesystem operations on directories and their contents. The
|
||||
Filesystem Library was developed to fill that void.</p>
|
||||
|
||||
<p>The intent is not to compete with traditional scripting languages, but to
|
||||
provide a solution for situations where C++ is already the language
|
||||
of choice..</p>
|
||||
|
||||
<h2><a name="Requirements">Requirements</a></h2>
|
||||
<ul>
|
||||
<li>Be able to write portable script-style filesystem operations in modern
|
||||
C++.<br>
|
||||
<br>
|
||||
Rationale: This is a common programming need. It is both an
|
||||
embarrassment and a hardship that this is not possible with either the current
|
||||
C++ or Boost libraries. The need is particularly acute
|
||||
when C++ is the only toolset allowed in the tool chain. File system
|
||||
operations are provided by many languages used on multiple platforms,
|
||||
such as Perl and Python, as well as by many platform specific scripting
|
||||
languages. All operating systems provide some form of API for filesystem
|
||||
operations, and the POSIX bindings are increasingly available even on
|
||||
operating systems not normally associated with POSIX, such as the Mac, z/OS,
|
||||
or OS/390.<br>
|
||||
</li>
|
||||
<li>Work within the <a href="#Realities">realities</a> described below.<br>
|
||||
<br>
|
||||
Rationale: This isn't a research project. The need is for something that works on
|
||||
today's platforms, including some of the embedded operating systems
|
||||
with limited file systems. Because of the emphasis on portability, such a
|
||||
library would be much more useful if standardized. That means being able to
|
||||
work with a much wider range of platforms that just Unix or Windows and their
|
||||
clones.<br>
|
||||
</li>
|
||||
<li>Avoid dangerous programming practices. Particularly, all-too-easy-to-ignore error notifications
|
||||
and use of global variables. If a dangerous feature is provided, identify it as such.<br>
|
||||
<br>
|
||||
Rationale: Normally this would be covered by "the usual Boost requirements...",
|
||||
but it is mentioned explicitly because the equivalent native platform and
|
||||
scripting language interfaces often depend on all-too-easy-to-ignore error
|
||||
notifications and global variables like "current
|
||||
working directory".<br>
|
||||
</li>
|
||||
<li>Structure the library so that it is still useful even if some functionality
|
||||
does not map well onto a given platform or directory tree. Particularly, much
|
||||
useful functionality should be portable even to flat
|
||||
(non-hierarchical) filesystems.<br>
|
||||
<br>
|
||||
Rationale: Much functionality which does not
|
||||
require a hierarchical directory structure is still useful on flat-structure
|
||||
filesystems. There are many systems, particularly embedded systems,
|
||||
where even very limited functionality is still useful.</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>Interface smoothly with current C++ Standard Library input/output
|
||||
facilities. For example, <a href="#filepath">file paths</a> should be
|
||||
easy to use in std::basic_fstream constructors.<br>
|
||||
<br>
|
||||
Rationale: One of the most common uses of file system functionality is to
|
||||
manipulate paths for eventual use in input/output operations.
|
||||
Thus the need to interface smoothly with standard library I/O.<br>
|
||||
</li>
|
||||
<li>Suitable for eventual standardization. The implication of this requirement
|
||||
is that the interface be close to minimal, and that great care be take
|
||||
regarding portability.<br>
|
||||
<br>
|
||||
Rationale: The lack of file system operations is a serious hole
|
||||
in the current standard, with no other known candidates to fill that hole.
|
||||
Libraries with elaborate interfaces and difficult to port specifications are much less likely to be accepted for
|
||||
standardization.<br>
|
||||
</li>
|
||||
<li>The usual Boost <a href="../../../more/lib_guide.htm">requirements and
|
||||
guidelines</a> apply.<br>
|
||||
</li>
|
||||
<li>Encourage, but do not require, portability in path names.<br>
|
||||
<br>
|
||||
Rationale: For paths which originate from user input it is unreasonable to
|
||||
require portable path syntax.<br>
|
||||
</li>
|
||||
<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
|
||||
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
|
||||
other sources exactly what behavior is required, yet for some reason it isn't
|
||||
possible to specify it exactly.</li>
|
||||
</ul>
|
||||
<h2><a name="Realities">Realities</a></h2>
|
||||
<ul>
|
||||
<li>Some file systems are single rooted, others are multi-rooted.<br>
|
||||
</li>
|
||||
<li>Some file systems provide both a long and short form of filenames.<br>
|
||||
</li>
|
||||
<li>Some file systems have different syntax for file paths and directory
|
||||
paths.<br>
|
||||
</li>
|
||||
<li>Some file systems have different rules for valid file names and valid
|
||||
directory names.<br>
|
||||
</li>
|
||||
<li>Some file systems (ISO-9660, level 1, for example) use very restricted
|
||||
(so-called 8.3) file names.<br>
|
||||
</li>
|
||||
<li>Some file systems allow other file systems with different
|
||||
characteristics to be "mounted" within a directory tree. Thus a
|
||||
ISO-9660 or Windows
|
||||
file system may end up as a sub-tree of a POSIX directory tree.<br>
|
||||
</li>
|
||||
<li>Wide-character versions of directory and file operations are available on some operating
|
||||
systems, and not available on others.<br>
|
||||
</li>
|
||||
<li>There is no law that says directory hierarchies have to be specified in
|
||||
terms of left-to-right decent from the root.<br>
|
||||
</li>
|
||||
<li>Some file systems have a concept of file "version number" or "generation
|
||||
number". Some don't.<br>
|
||||
</li>
|
||||
<li>Not all file systems use single character separators in path names. Some use
|
||||
paired notations. A typical fully-specified OpenVMS filename
|
||||
might look something like this:<br>
|
||||
<br>
|
||||
<code> DISK$SCRATCH:[GEORGE.PROJECT1.DAT]BIG_DATA_FILE.NTP;5<br>
|
||||
</code><br>
|
||||
The general OpenVMS format is:<br>
|
||||
<br>
|
||||
|
||||
<i>Device:[directories.dot.separated]filename.extension;version_number</i><br>
|
||||
</li>
|
||||
<li>For common file systems, determining if two descriptors are for same
|
||||
entity is extremely difficult or impossible. For example, the concept of
|
||||
equality can be different for each portion of a path - some portions may be
|
||||
case or locale sensitive, others not. Case sensitivity is a property of the
|
||||
pathname itself, and not the platform. Determining collating sequence is even
|
||||
worse.<br>
|
||||
</li>
|
||||
<li>Race-conditions may occur. Directory trees, directories, files, and file attributes are in effect shared between all threads, processes, and computers which have access to the
|
||||
filesystem. That may well include computers on the other side of the
|
||||
world or in orbit around the world. This implies that file system operations
|
||||
may fail in unexpected ways. For example:<br>
|
||||
<br>
|
||||
<code> assert( exists("foo") == exists("foo") );
|
||||
// may fail!<br>
|
||||
assert( is_directory("foo") == is_directory("foo");
|
||||
// may fail!<br>
|
||||
</code><br>
|
||||
In the first example, the file may have been deleted between calls to
|
||||
exists(). In the second example, the file may have been deleted and then
|
||||
replaced by a directory of the same name between the calls to is_directory().<br>
|
||||
</li>
|
||||
<li>Even though an application may be portable, it still will have to traffic
|
||||
in system specific paths occasionally; user provided input is a common
|
||||
example.</li>
|
||||
</ul>
|
||||
|
||||
<h2><a name="Rationale">Rationale</a></h2>
|
||||
|
||||
<p>The <a href="#Requirements">Requirements</a> and <a href="#Realities">
|
||||
Realities</a> above drove much of the C++ interface design. In particular,
|
||||
the desire to make script-like code straightforward caused a great deal of
|
||||
effort to go into ensuring that apparently simple expressions like <i>exists( "foo"
|
||||
)</i> work as expected.</p>
|
||||
|
||||
<p>See the <a href="faq.htm">FAQ</a> for the rationale behind many detailed
|
||||
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>
|
||||
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>
|
||||
</ul>
|
||||
|
||||
<p>Error checking was a particularly difficult area. One key insight was that
|
||||
with file and directory names, portability isn't a universal truth.
|
||||
Rather, the programmer must think out the question "What operating systems do I
|
||||
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>
|
||||
<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
|
||||
discussions among Library Working Group members failed to identify portable
|
||||
semantics for wide-character names on systems not providing native support. See
|
||||
<a href="faq.htm#wide-character names">FAQ</a>.</p>
|
||||
<p>Previous iterations of the interface design used explicitly named functions providing a
|
||||
large number of convenience operations, with no compile-time or run-time
|
||||
options. There were so many function names that they were very confusing to use,
|
||||
and the interface was much larger. Any benefits seemed theoretical rather than
|
||||
real. </p>
|
||||
<p>Designs based on compile time (rather than runtime) flag and option selection
|
||||
(via policy, enum, or int template parameters) became so complicated that they
|
||||
were abandoned, often after investing quite a bit of time and effort. The need
|
||||
to qualify attribute or option names with namespaces, even aliases, made use in
|
||||
template parameters ugly; that wasn't fully appreciated until actually writing
|
||||
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>
|
||||
|
||||
<h3>path.hpp</h3>
|
||||
|
||||
<p>There were so many abandoned path designs, I've lost track. Policy-based
|
||||
class templates in several flavors, constructor supplied runtime policies,
|
||||
operation specific runtime policies, they were all considered, often
|
||||
implemented, and ultimately abandoned as far too complicated for any small
|
||||
benefits observed.</p>
|
||||
|
||||
<h3>error checking</h3>
|
||||
|
||||
<p>A number of designs for the error checking machinery were abandoned, some
|
||||
after experiments with implementations. Totally automatic error checking was
|
||||
attempted in particular. But automatic error checking tended to make the overall
|
||||
library design much more complicated.</p>
|
||||
|
||||
<p>Some designs associated error checking mechanisms with paths. Some with
|
||||
operations functions. A policy-based error checking template design was
|
||||
partially implemented, then abandoned as too complicated for everyday
|
||||
script-like programs.</p>
|
||||
|
||||
<p>The final design, which depends partially on explicit error checking function
|
||||
calls, is much simpler and straightforward, although it does depend to
|
||||
some extent on programmer discipline. But it should allow programmers who
|
||||
are concerned about portability to be reasonably sure that their programs will
|
||||
work correctly on their choice of target systems.</p>
|
||||
|
||||
<h2><a name="References">References</a></h2>
|
||||
|
||||
<p>[<a name="IBM-01">IBM-01</a>] IBM Corporation, <i>z/OS V1R3.0 C/C++ Run-Time
|
||||
Library Reference</i>, SA22-7821-02, 2001,
|
||||
<a href="http://www-1.ibm.com/servers/eserver/zseries/zos/bkserv/">
|
||||
http://www-1.ibm.com/servers/eserver/zseries/zos/bkserv/</a></p>
|
||||
|
||||
<p>[<a name="ISO-9660">ISO-9660</a>] International Standards Organization, 1988.</p>
|
||||
|
||||
<p>[<a name="POSIX-01">POSIX-01</a>] Open Group, <i>IEEE Std 1003.1-2001 [AKA
|
||||
POSIX]</i>, 2001,
|
||||
<a href="http://www.opengroup.org/onlinepubs/007904975/toc.htm">
|
||||
http://www.opengroup.org/onlinepubs/007904975/toc.htm</a></p>
|
||||
|
||||
<p>[<a name="Wulf-Shaw-73">Wulf-Shaw-73</a>] William Wulf, Mary Shaw, <i>Global
|
||||
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>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
45
doc/do-list.htm
Normal file
45
doc/do-list.htm
Normal file
@ -0,0 +1,45 @@
|
||||
<title>Boost Filesystem Do-list</title>
|
||||
<h1>
|
||||
<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>
|
||||
<li>Finish portability guide and checking functions. Get opinions on default, Boost, and other error checks. POSIX?
|
||||
Windows? Mac? ISO 6990?<br>
|
||||
</li>
|
||||
<li>Cyclic paths:</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<ul>
|
||||
<li>General requirements.</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>
|
||||
</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>
|
||||
<li>Once the review is complete, ask for help porting to the Mac, etc.<br>
|
||||
</li>
|
||||
<li>From John Maddock:</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>
|
||||
</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>
|
31
doc/exception.htm
Normal file
31
doc/exception.htm
Normal file
@ -0,0 +1,31 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Language" content="en-us">
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<title>Boost Filesystem exception.hpp Header</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF">
|
||||
|
||||
<h1>
|
||||
<img border="0" src="../../../c++boost.gif" align="center" width="277" height="86"><a href="../../../boost/filesystem/exception.hpp">boost/filesystem/exception.hpp</a></h1>
|
||||
|
||||
<h2><a name="Introduction">Introduction</a></h2>
|
||||
|
||||
<p>The header provides class <i>filesystem_error</i>, publicly derived from <i>
|
||||
std::runtime_error</i>, which is used by functions in the Filesystem Library to
|
||||
report operational errors.</p>
|
||||
|
||||
<p>There isn't any HTML documentation available yet. The header itself, <a href="../../../boost/filesystem/exception.hpp">boost/filesystem/exception.hpp</a>,
|
||||
contains comments as to the specifications for important member functions.</p>
|
||||
<hr>
|
||||
<p>© Copyright Beman Dawes, 2002</p>
|
||||
<p>Revised
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->11 July, 2002<!--webbot bot="Timestamp" endspan i-checksum="21079" --></p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
178
doc/faq.htm
Normal file
178
doc/faq.htm
Normal file
@ -0,0 +1,178 @@
|
||||
<title>Boost Filesystem FAQ</title>
|
||||
<body bgcolor="#FFFFFF">
|
||||
|
||||
<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
|
||||
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 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>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>
|
||||
<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>
|
||||
<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
|
||||
file system operations" requirement with such a system. File systems exist where operations are usually performed on
|
||||
some non-string handle type. The classic Mac OS has been mentioned explicitly as a case where
|
||||
trafficking in paths isn't always natural. </p>
|
||||
<p>The case for the "handle" (opaque data type to identify a file)
|
||||
style may be strongest for directory iterator value type. (See Jesse Jones' Jan 28,
|
||||
2002, Boost postings). However, as class path has evolved, it seems sufficient
|
||||
even as the directory iterator value type.</p>
|
||||
<p><b>Why aren't directories considered to be files?</b></p>
|
||||
<p>Because
|
||||
directories cannot portably and usefully be opened as files using the C++ Standard Library stdio or fstream
|
||||
I/O facilities. An important additional rationale is that separating the concept
|
||||
of directories and files makes exposition and specification clearer. A
|
||||
particular problem is the naming and description of function arguments.</p>
|
||||
<div align="center">
|
||||
<center>
|
||||
<table border="1" cellpadding="5" cellspacing="0">
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
<p align="center"><b>Meaningful Names for Arguments</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Argument Intent</b></td>
|
||||
<td><b>Meaningful name if<br>
|
||||
directories are files</b></td>
|
||||
<td><b>Meaningful name if<br>
|
||||
directories aren't files</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>A path to either a directory or a non-directory</td>
|
||||
<td align="center"><i>path</i></td>
|
||||
<td align="center"><i>path</i></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>A path to a directory, but not to a non-directory</td>
|
||||
<td align="center"><i>directory_path</i></td>
|
||||
<td align="center"><i>directory_path</i></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>A path to a non-directory, but not a directory</td>
|
||||
<td align="center"><i>non_directory_path</i></td>
|
||||
<td align="center"><i>file_path</i></td>
|
||||
</tr>
|
||||
</table>
|
||||
</center>
|
||||
</div>
|
||||
<p>The problem is that when directories are considered files, <i>
|
||||
non_directory_path</i> as an argument name, and the corresponding "non-directory
|
||||
path" in documentation, is ugly and lengthy, and so is shortened to just <i>path</i>,
|
||||
causing the code and documentation to be confusing if not downright wrong. The
|
||||
names which result from the "directories aren't files" approach are more
|
||||
acceptable and less likely to be used incorrectly. </p>
|
||||
<p><b>Why are the operations.hpp non-member functions so low-level?</b></p>
|
||||
<p>To provide a toolkit from which higher-level functionality can be created.</p>
|
||||
<p>An
|
||||
extended attempt to add convenience functions on top of, or as a replacement
|
||||
for, the low-level functionality failed because there is no widely acceptable
|
||||
set of simple semantics for most convenience functions considered.
|
||||
Attempts to provide alternate semantics, via either run-time options or
|
||||
compile-time polices, became overly complicated in relation to the value
|
||||
delivered, or became contentious. OTOH, the specific functionality needed for several trial
|
||||
applications was very easy for the user to construct from the lower-level
|
||||
toolkit functions. See <a href="#Failed Attempts">Failed Attempts</a>.</p>
|
||||
<p><b>Isn't it inconsistent then to provide a few convenience functions?</b></p>
|
||||
<p>Yes, but experience with both this library, POSIX, and Windows indicates
|
||||
the utility of certain convenience functions, and that it is possible to provide
|
||||
simple, yet widely acceptable, semantics for them. For example, remove_all.</p>
|
||||
<p><b>Why are library functions so picky about errors?</b></p>
|
||||
<p>Safety. The default is to be safe rather than sorry. This is particularly
|
||||
important given the reality that on many computer systems files and directories
|
||||
are <a href="#global">globally shared</a> resources .</p>
|
||||
<p><b>Why are errors reported by exception rather than return code or error
|
||||
notification variable?</b></p>
|
||||
<p>Safety. Return codes or error notification variables are often ignored
|
||||
by programmers. Exceptions are much harder to ignore, provided desired
|
||||
default behavior (program termination) if not caught, yet allow error recovery
|
||||
if desired.</p>
|
||||
<p><b>Why are attributes accessed via named functions rather than property maps?</b></p>
|
||||
<p>For a few commonly used attributes (existence, directory or file, emptiness),
|
||||
simple syntax and guaranteed presence outweigh other considerations. Because
|
||||
access to virtually all other attributes is inherently system dependent,
|
||||
property maps are viewed as the best hope for access and modification, but it is
|
||||
better design to provide such functionality in a separate library. (Historical
|
||||
note: even the apparently simple attribute "read-only" turned out to be so
|
||||
system depend as to be disqualified as a "guaranteed presence" operation.)</p>
|
||||
<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>
|
||||
<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
|
||||
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
|
||||
operating systems (Windows, for example) that support wide-character names, than
|
||||
on systems which don't (POSIX). Providing functionality that appears to provide
|
||||
portability but in fact delivers only implementation-defined behavior is highly
|
||||
undesirable. Programs would not even be portable between library implementations
|
||||
on the same operating system, let alone portable to different operating systems.</p>
|
||||
<p>The C++ standards committee Library Working Group discussed this in some
|
||||
detail both on the committee's library reflector and at the Spring, 2002, <font face="Times New Roman"> meeting</font>, and feels that (1) names based on types other than char are
|
||||
extremely non-portable, (2) there are no agreed upon semantics for conversion
|
||||
between wide-character and narrow-character names for file systems which do not support
|
||||
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><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
|
||||
where non-portable names constitute errors vary widely. For example, a
|
||||
non-portable name found by a <i>directory_iterator</i> may or may not constitute
|
||||
an application error. In another example, for an application copying selected
|
||||
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
|
||||
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>
|
107
doc/fstream.htm
Normal file
107
doc/fstream.htm
Normal file
@ -0,0 +1,107 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Language" content="en-us">
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<title>Boost Filesystem fstream Header</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF">
|
||||
|
||||
<h1>
|
||||
<img border="0" src="../../../c++boost.gif" align="center" width="277" height="86"><a href="../../../boost/filesystem/fstream.hpp">boost/filesystem/fstream.hpp</a></h1>
|
||||
|
||||
<h2><a name="Introduction">Introduction</a></h2>
|
||||
|
||||
<p>The C++ Standard Library's <i><fstream></i> header uses <i>const char*</i> to
|
||||
pass arguments representing file names, with that usage occurring seven
|
||||
times.</p>
|
||||
|
||||
<p>The Filesystem Library's <i>fstream.hpp</i> header provides equivalent
|
||||
components, in namespace <i>
|
||||
boost::filesystem</i>, except that the seven <i>
|
||||
const char*</i> arguments have been replaced by <i>const path&</i> arguments.</p>
|
||||
|
||||
<p>The Filesystem Library's <i>fstream.hpp</i> header simply uses the <i><fstream></i> standard library
|
||||
components as base classes, and then overrides the members requiring argument
|
||||
types of <i>path</i>.</p>
|
||||
|
||||
<p>For documentation beyond the synopsis, see the
|
||||
<a href="index.htm#tutorial">tutorial</a> and <a href="index.htm#Examples">
|
||||
examples</a>.</p>
|
||||
|
||||
<h2><a name="Synopsis">Synopsis</a></h2>
|
||||
<pre>namespace boost
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
template < class charT, class traits = std::char_traits<charT> >
|
||||
class basic_filebuf : public std::basic_filebuf<charT,traits>
|
||||
{
|
||||
public:
|
||||
virtual ~basic_filebuf() {}
|
||||
|
||||
std::basic_filebuf<charT,traits> * open( const path & file_ph,
|
||||
std::ios_base::openmode mode );
|
||||
};
|
||||
|
||||
typedef basic_filebuf<char> filebuf;
|
||||
typedef basic_filebuf<wchar_t> wfilebuf;
|
||||
|
||||
template < class charT, class traits = std::char_traits<charT> >
|
||||
class basic_ifstream : public std::basic_ifstream<charT,traits>
|
||||
{
|
||||
public:
|
||||
basic_ifstream() {}
|
||||
explicit basic_ifstream( const path & file_ph,
|
||||
std::ios_base::openmode mode = std::ios_base::in );
|
||||
virtual ~basic_ifstream() {}
|
||||
void open( const path & file_ph,
|
||||
std::ios_base::openmode mode = std::ios_base::in );
|
||||
};
|
||||
|
||||
typedef basic_ifstream<char> ifstream;
|
||||
typedef basic_ifstream<wchar_t> wifstream;
|
||||
|
||||
template < class charT, class traits = std::char_traits<charT> >
|
||||
class basic_ofstream : public std::basic_ofstream<charT,traits>
|
||||
{
|
||||
public:
|
||||
basic_ofstream() {}
|
||||
explicit basic_ofstream( const path & file_ph,
|
||||
std::ios_base::openmode mode = std::ios_base::out );
|
||||
virtual ~basic_ofstream() {}
|
||||
void open( const path & file_ph,
|
||||
std::ios_base::openmode mode = std::ios_base::out );
|
||||
};
|
||||
|
||||
typedef basic_ofstream<char> ofstream;
|
||||
typedef basic_ofstream<wchar_t> wofstream;
|
||||
|
||||
template < class charT, class traits = std::char_traits<charT> >
|
||||
class basic_fstream : public std::basic_fstream<charT,traits>
|
||||
{
|
||||
public:
|
||||
basic_fstream() {}
|
||||
explicit basic_fstream( const path & file_ph,
|
||||
std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out );
|
||||
virtual ~basic_fstream() {}
|
||||
void open( const path & file_ph,
|
||||
std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out );
|
||||
};
|
||||
|
||||
typedef basic_fstream<char> fstream;
|
||||
typedef basic_fstream<wchar_t> wfstream;
|
||||
} // namespace filesystem
|
||||
} // namespace boost
|
||||
</pre>
|
||||
<hr>
|
||||
<p>© Copyright Beman Dawes, 2002</p>
|
||||
<p>Revised
|
||||
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->14 September, 2002<!--webbot bot="Timestamp" endspan i-checksum="39338" --></p>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
288
doc/index.htm
Normal file
288
doc/index.htm
Normal file
@ -0,0 +1,288 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Language" content="en-us">
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<title>Boost Filesystem Library</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF">
|
||||
|
||||
<h1>
|
||||
<img border="0" src="../../../c++boost.gif" align="center" width="277" height="86">Boost
|
||||
Filesystem Library</h1>
|
||||
<table border="0" cellpadding="0" width="100%">
|
||||
<tr>
|
||||
<td width="50%" valign="top"><font size="4">This Document</font><br>
|
||||
<a href="#Introduction">Introduction</a><br>
|
||||
<a href="#tutorial">Two-minute tutorial</a><br>
|
||||
<a href="#Examples">Examples</a><br>
|
||||
|
||||
<a href="#Definitions">Definitions</a><br>
|
||||
|
||||
<a href="#Requirements">Requirements</a><br>
|
||||
<a href="#Race-condition">Race-condition danger</a><br>
|
||||
<a href="#Acknowledgements">Acknowledgements</a></td>
|
||||
<td width="50%"><font size="4">Other Documents</font><br>
|
||||
<a href="design.htm">Library Design</a><br>
|
||||
<a href="faq.htm">FAQ</a><br>
|
||||
<a href="portability_guide.htm">Portability Guide</a><br>
|
||||
<a href="path.htm"><b><i>path.hpp</i></b> documentation</a><br>
|
||||
<a href="operations.htm"><b><i>operations.hpp</i></b> documentation</a><br>
|
||||
<a href="fstream.htm"><b><i>fstream.hpp</i></b> documentation</a><br>
|
||||
<a href="exception.htm"><b><i>exception.hpp</i></b> documentation</a><br>
|
||||
<a href="do-list.htm">Do-list</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<h2><a name="Introduction">Introduction</a></h2>
|
||||
<p>The Boost Filesystem Library provides portable facilities to query and
|
||||
manipulate paths, files, and directories.</p>
|
||||
|
||||
<p>The motivation for the library is the need to be able to perform portable script-like operations from within C++ programs. The intent is not to
|
||||
compete with Python, Perl, or shell languages, but rather to provide portable filesystem
|
||||
operations when C++ is already the language of choice. The <a href="design.htm">
|
||||
design</a> encourages, but does not require, safe and portable filesystem usage.</p>
|
||||
|
||||
<p>Filesystem Library components are supplied by several headers, all in
|
||||
directory boost/filesystem:</p>
|
||||
|
||||
<ul>
|
||||
<li>Header <i>path.hpp</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,
|
||||
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
|
||||
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
|
||||
<a href="exception.htm">exception.hpp documentation</a>.<br>
|
||||
</li>
|
||||
<li>Experimental header <i>
|
||||
<a href="../../../boost/filesystem/recursive_directory_iterator.hpp">
|
||||
recursive_directory_iterator.hpp</a></i> provides an undocumented directory
|
||||
iterator which recurses into any sub-directories encountered. It will be
|
||||
incorporated into the Filesystem Library if user feedback is favorable.</li>
|
||||
</ul>
|
||||
<h2>Two-minute <a name="tutorial">tutorial</a></h2>
|
||||
<p>First some preliminaries:</p>
|
||||
<blockquote>
|
||||
<pre>#include "boost/filesystem/operations.hpp" // includes boost/filesystem/path.hpp
|
||||
#include "boost/filesystem/fstream.hpp" // ditto
|
||||
#include <iostream> // for cout
|
||||
namespace fs = boost::filesystem;</pre>
|
||||
</blockquote>
|
||||
<p>A <a href="path.htm#synopsis">class <i>path</i></a> object can be created:</p>
|
||||
<blockquote>
|
||||
<pre>fs::path my_path( "some_dir/file.txt" );</pre>
|
||||
</blockquote>
|
||||
<p>The string passed to the <i>path</i> constructor is in a
|
||||
<a href="path.htm#Grammar">portable generic path format</a>. Access functions
|
||||
make <i>my_path</i> contents available in an operating system dependent format,
|
||||
such as <code>"some_dir:file.txt"</code>, <code>"[some_dir]file.txt"</code>,
|
||||
<code>"some_dir/file.txt"</code>, or whatever is appropriate for the
|
||||
operating system.</p>
|
||||
<p>Class <i>path</i> has conversion constructors from <i>const char*</i> and <i>
|
||||
const std:: string&</i>, so that even though the Filesystem Library functions in
|
||||
the following code snippet take <i>const path&</i> arguments, the user can just
|
||||
code C-style strings:</p>
|
||||
<blockquote>
|
||||
<pre>fs::remove_all( "foobar" );
|
||||
fs::create_directory( "foobar" );
|
||||
fs::ofstream file( "foobar/cheeze" );
|
||||
file << "tastes good!\n";
|
||||
file.close();
|
||||
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>
|
||||
<blockquote>
|
||||
<pre>int main( int argc, char * argv[] ) {
|
||||
fs::path arg_path( argv[1], fs::system_specific );</pre>
|
||||
</blockquote>
|
||||
<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>
|
||||
</blockquote>
|
||||
<p>Note that expressions <i>arg_path << "foo/bar"</i> and <i>arg_path << "foo"
|
||||
<< "bar"</i> yield equivalent 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>
|
||||
<p>The following function, given a directory path and a file name, recursively
|
||||
searches the directory and its sub-directories for the file name, returning a
|
||||
bool, and if successful, the path to the file that was found. The code
|
||||
below is extracted from a real program, slightly modified for clarity:</p>
|
||||
<blockquote>
|
||||
<pre>bool find_file( const fs::path & dir_path, // in this directory,
|
||||
const std::string & file_name, // search for this name,
|
||||
fs::path & path_found ) // placing path here if found
|
||||
{
|
||||
if ( !fs::exists( dir_path ) ) return false;
|
||||
fs::directory_iterator end_itr; // default construction yields past-the-end
|
||||
for ( fs::directory_iterator itr( dir_path );
|
||||
itr != end_itr;
|
||||
++itr )
|
||||
{
|
||||
if ( fs::is_directory( *itr ) )
|
||||
{
|
||||
if ( find_file( *itr, file_name, path_found ) ) return true;
|
||||
}
|
||||
else if ( itr->leaf() == file_name ) // see below
|
||||
{
|
||||
path_found = *itr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}</pre>
|
||||
</blockquote>
|
||||
<p>The expression <i>itr->leaf() == file_name</i>, in the line commented <i>//
|
||||
see below</i>, calls the <i>leaf()</i> function on the <i>path</i> object
|
||||
returned by the iterator. <i>leaf()</i> returns a string which is a copy of the
|
||||
last (closest to the leaf, farthest from the root) file or directory name in the
|
||||
<i>path</i> object.</p>
|
||||
<p>Notice that <i>find_file()</i> does not do explicit error checking, such as
|
||||
verifying that the <i>dir_path</i> argument really represents a directory. All
|
||||
Filesystem Library functions throw <a href="exception.htm">filesystem_error</a>
|
||||
exceptions if they do not complete successfully, so there is enough implicit
|
||||
error checking that this application doesn't need to include additional error
|
||||
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
|
||||
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>
|
||||
<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>
|
||||
<h2><a name="Definitions">Definitions</a></h2>
|
||||
<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
|
||||
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>
|
||||
which contains the
|
||||
next element. The last element may name either a directory or file. The first
|
||||
element is closest to the root of the directory tree, the last element is
|
||||
farthest from the root.</p>
|
||||
<p>It is traditional to represent a path as a string, where each element in the
|
||||
path is represented by a <a href="#name">name</a>, and some operating system
|
||||
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>
|
||||
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
|
||||
directory's actual location within a directory tree. For some
|
||||
operating systems, files and directories may have more than one valid name, such
|
||||
as a short-form name and a long-form name.</p>
|
||||
<h2><a name="Requirements">Requirements</a></h2>
|
||||
<p>Unless otherwise specified, all Filesystem Library functions are required to
|
||||
throw a <i><a href="exception.htm">filesystem_error</a></i> exception if the
|
||||
implementation cannot successfully complete operations required to meet the
|
||||
function's specifications. Such exceptions are in addition to any exceptions
|
||||
specified in the function's "Throws" paragraph.</p>
|
||||
<p>Filesystem Library functions are permitted to call C++ Standard Library
|
||||
functions, so <i>std::bad_alloc</i> exceptions may also be thrown, unless
|
||||
otherwise specified.</p>
|
||||
<p>There is no rollback guarantee; a Filesystem Library function which throws an
|
||||
exception may leave the external file system in an altered state.</p>
|
||||
<h2><a name="Race-condition">Race-condition</a> d<a name="Dangers">anger</a></h2>
|
||||
<p>The state of files and directories is often
|
||||
globally shared, and thus may be changed unexpectedly by other threads,
|
||||
processes, or even other computers which have access to the filesystem. As an
|
||||
example of the difficulties this can cause, consider that the following asserts
|
||||
may fail:</p>
|
||||
<blockquote>
|
||||
<p><code>assert( exists( "foo" ) == exists( "foo" ) ); //
|
||||
(1)<br>
|
||||
<br>
|
||||
remove_all( "foo" );<br>
|
||||
assert( !exists( "foo" ) ); // (2)<br>
|
||||
<br>
|
||||
assert( is_directory( "foo" ) == is_directory( "foo" ) ); //
|
||||
(3)</code></p>
|
||||
</blockquote>
|
||||
<p>(1) will fail if a non-existent "foo" comes into existence, or an
|
||||
existent "foo" is removed, between the first and second call to <i>exists()</i>.
|
||||
This could happen if, during the execution of the example code, another thread,
|
||||
process, or computer is also performing operations in the same directory.</p>
|
||||
<p>(2) will fail if between the call to <i>remove_all()</i> and the call to
|
||||
<i>exists()</i> a new file or directory named "foo" is created by another
|
||||
thread, process, or computer.</p>
|
||||
<p>(3) will fail if another thread, process, or computer removes an
|
||||
existing file "foo" and then creates a directory named "foo", between the
|
||||
example code's two calls to <i>is_directory()</i>.</p>
|
||||
<p>A program which needs to be robust when operating on potentially-shared file
|
||||
or directory resources should be prepared for <i>filesystem_error</i> exceptions
|
||||
to be thrown from any filesystem function except those explicitly specified as
|
||||
not throwing exceptions.</p>
|
||||
<h2><a name="Implementation">Implementation</a></h2>
|
||||
<p>The current implementation (September, 2002) supports operating systems that have
|
||||
either the POSIX or Windows API's available.</p>
|
||||
<p>The following tests are provided:</p>
|
||||
<ul>
|
||||
<li><a href="../test/path_test.cpp">path_test.cpp</a></li>
|
||||
<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>
|
||||
<ul>
|
||||
<li>Borland 5.5.1</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>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>
|
||||
<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>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>
|
||||
|
||||
<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>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
298
doc/operations.htm
Normal file
298
doc/operations.htm
Normal file
@ -0,0 +1,298 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Language" content="en-us">
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<title>Boost Filesystem operations.hpp Header</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF">
|
||||
|
||||
<h1>
|
||||
<img border="0" src="../../../c++boost.gif" align="center" width="277" height="86"><a href="../../../boost/filesystem/operations.hpp">boost/filesystem/operations.hpp</a></h1>
|
||||
|
||||
<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="#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="#exists">exists</a><br>
|
||||
<a href="#is_directory">is_directory</a><br>
|
||||
<a href="#is_empty">is_empty</a><br>
|
||||
<a href="#create_directory">create_directory</a><br>
|
||||
<a href="#remove">remove</a><br>
|
||||
<a href="#remove_all">remove_all</a><br>
|
||||
<a href="#rename">rename</a><br>
|
||||
<a href="#copy_file">copy_file</a><br>
|
||||
<a href="#initial_directory">initial_directory</a></p>
|
||||
|
||||
<h2><a name="Introduction">Introduction</a></h2>
|
||||
|
||||
<p>The <a href="../../../boost/filesystem/operations.hpp">
|
||||
boost/filesystem/operations.hpp</a> header provides operations on files and
|
||||
directories.</p>
|
||||
|
||||
<p>These operations traffic in paths; see <a href="path.htm">
|
||||
boost/filesystem/path.hpp documentation</a>.</p>
|
||||
|
||||
<p>For file I/O streams, see <a href="fstream.htm">boost/filesystem/fstream.hpp
|
||||
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>Header <a href="../../../boost/filesystem/operations.hpp">boost/filesystem/operations.hpp</a>
|
||||
<a name="Synopsis">synopsis</a></h2>
|
||||
<pre>namespace boost
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
|
||||
class <a href="#Class directory_iterator">directory_iterator</a>
|
||||
{
|
||||
public:
|
||||
typedef <a href="path.htm">path</a> value_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef const path * pointer;
|
||||
typedef const path & reference;
|
||||
typedef std::input_iterator_tag iterator_category;
|
||||
|
||||
<a href="#constructors">directory_iterator</a>();
|
||||
explicit <a href="#constructors">directory_iterator</a>( const path & directory_ph );
|
||||
|
||||
// <a href="#other functions">other functions</a>
|
||||
// ...
|
||||
};
|
||||
|
||||
bool <a href="#exists">exists</a>( const path & ph );
|
||||
bool <a href="#is_directory">is_directory</a>( const path & ph );
|
||||
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 );
|
||||
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>();
|
||||
|
||||
} // namespace filesystem
|
||||
} // namespace boost
|
||||
</pre>
|
||||
|
||||
<h2><a name="Class 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">
|
||||
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">
|
||||
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
|
||||
the directory entry to the directory path supplied at construction.</p>
|
||||
|
||||
<p>The order of the path entries returned by dereferencing successive increments
|
||||
of a <i>directory_iterator</i> is unspecified. Thus depending on the ordering
|
||||
provided by a particular implementation will result in non-portable code.</p>
|
||||
|
||||
<p>A path returned by dereferencing a <i>directory_iterator</i> is, if
|
||||
representing a directory, suitable for use as an argument to Filesystem Library
|
||||
functions specified as accepting paths or directory paths. If not representing a
|
||||
directory, the dereferenced path is suitable for use as an argument to
|
||||
Filesystem Library functions specified as accepting paths or file paths, or C++
|
||||
Standard Library functions specified as taking file names. The leaf of a path
|
||||
returned by dereferencing a <i>directory_iterator</i> will never be <code>".."</code>
|
||||
or <code>"."</code>.</p>
|
||||
|
||||
<p><b>Note:</b> The implication of the above requirement is that if an operating
|
||||
system's directories can contain entries which are not usable by Filesystem
|
||||
Library or Standard Library functions, these entries will be skipped during
|
||||
directory iteration. Such entries are by definition non-portable, but can always
|
||||
be accessed via the native operating system API if required.</p>
|
||||
|
||||
<h3><a name="constructors">Constructors</a></h3>
|
||||
<blockquote>
|
||||
|
||||
<p><code>directory_iterator();</code></p>
|
||||
|
||||
<p><b>Effects:</b> Constructs a <i>directory_iterator</i> having the <i>
|
||||
past-the-end</i> value as described in the C++ standard, section 24.1.</p>
|
||||
|
||||
<p><code>explicit directory_iterator( const path & directory_ph );</code></p>
|
||||
|
||||
<p><b>Effects:</b> Constructs a <i>directory_iterator</i> with a value
|
||||
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>
|
||||
|
||||
<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>
|
||||
|
||||
<p>
|
||||
The non-member functions provide common operations on files and directories.
|
||||
They follow traditional practice of the C and C++ standard libraries, except
|
||||
that
|
||||
they:</p>
|
||||
|
||||
<ul>
|
||||
<li>Traffic in <i><a href="path.htm">paths</a></i> rather than <code>char*</code>'s, for much
|
||||
enhanced portability.</li>
|
||||
<li>Report errors by throwing exceptions, for safer and better error handling.</li>
|
||||
<li>Tighten specifications slightly, for improved portability.</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
<b>Rationale:</b> Functions which already exist in the C++ Standard Library,
|
||||
such as <i><a href="#remove">remove()</a></i> and <i><a href="#rename">rename()</a></i>,
|
||||
retain the same names and general behavior in the Filesystem Library, to
|
||||
minimize surprises.</p>
|
||||
|
||||
<p>
|
||||
<b>Rationale:</b> Errors which might appear to be preconditions are not
|
||||
specified as such, but instead are specified to throw exceptions. This is
|
||||
because the possibility of <a href="index.htm#Race-condition">race-conditions</a>
|
||||
makes it unreliable to test for preconditions before calling the function. As a
|
||||
design practice, preconditions should always be testable by a program, so that
|
||||
violations can be avoided. It is not always possible or desirable to abstract
|
||||
away the fact that the library is implemented by calls to the operating system,
|
||||
and this is one of those cases.</p>
|
||||
|
||||
<p>
|
||||
<b>Naming Rationale:</b> See class <i>path</i>
|
||||
<a href="path.htm#Naming Rationale">Naming Rationale</a>.</p>
|
||||
|
||||
<h3><a name="exists">exists</a></h3>
|
||||
<blockquote>
|
||||
<p><code>bool exists( const path & ph );</code></p>
|
||||
<p><b>Returns:</b> True if the operating system reports the path
|
||||
represented by <i>ph</i> exists, else false.</p>
|
||||
<p><b>Note: </b>Even if <i>exists( ph ) == true</i>, there is no guarantee that it
|
||||
will be possible to perform other operations on the file or directory. Access
|
||||
rights or other security concerns, for example, may cause other operations to
|
||||
fail.</p>
|
||||
</blockquote>
|
||||
<h3><a name="is_directory">is_directory</a></h3>
|
||||
<blockquote>
|
||||
<p><code>bool is_directory( const path & ph );</code></p>
|
||||
<p><b>Returns:</b> True if the operating system reports the path represented by
|
||||
<i>ph</i> is a directory, else false.</p>
|
||||
<p><b>Throws:</b> if <code>!exists(ph)</code></p>
|
||||
<p><b>Rationale:</b> Treating <code>!exists(ph)</code> as an exception rather
|
||||
than just returning false came about because in real code <code>!exists(ph)</code>
|
||||
has
|
||||
often been the first indicate of a programming error. A compound function returning <code>
|
||||
exists(ph) && is_directory(ph)</code> can always be added later.</p>
|
||||
</blockquote>
|
||||
<h3><a name="is_empty">is_empty</a></h3>
|
||||
<blockquote>
|
||||
<p><code>bool is_empty( const path & ph );</code></p>
|
||||
<p><b>Returns:</b> True if the operating system reports the path represented by
|
||||
<i>ph</i> is an empty file or empty directory, else false.</p>
|
||||
<p><b>Throws:</b> if <code>!exists(path)</code></p>
|
||||
</blockquote>
|
||||
<h3><a name="create_directory">create_directory</a></h3>
|
||||
<blockquote>
|
||||
<p><code>void create_directory( const path & directory_ph );</code></p>
|
||||
<p><b>Postcondition:</b> <code>exists(directory_ph) &&
|
||||
is_directory(directory_ph) && is_empty(directory_ph)</code></p>
|
||||
<p><b>Throws: </b>if <code>exists(directory_ph)) || !exists(branch(directory_ph))</code></p>
|
||||
</blockquote>
|
||||
<h3><a name="remove">remove</a></h3>
|
||||
<blockquote>
|
||||
<p><code>void remove( const path & ph );</code></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
|
||||
throwing is:</p>
|
||||
<ul>
|
||||
<li>Slightly easier-to-use for many common use cases.</li>
|
||||
<li>Slightly higher-level because it implies use of postcondition semantics
|
||||
rather than effects semantics, which would be specified in the somewhat
|
||||
lower-level terms of interactions with the operating system.</li>
|
||||
</ul>
|
||||
<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>
|
||||
</blockquote>
|
||||
<h3><a name="remove_all">remove_all</a></h3>
|
||||
<blockquote>
|
||||
<p><code>unsigned long remove_all( const path & ph );</code></p>
|
||||
<p><b>Postcondition:</b> <code>!exists( ph )</code></p>
|
||||
<p><b>Returns:</b> The number of files and directories removed.</p>
|
||||
</blockquote>
|
||||
<h3><a name="rename">rename</a></h3>
|
||||
<blockquote>
|
||||
<p><code>void rename( const path & from_ph, const path & to_ph
|
||||
);</code></p>
|
||||
<p><b>Effects:</b> Changes the name of file or directory <i>from_ph</i>
|
||||
to <i>to_ph</i>.</p>
|
||||
<p><b>Postconditions:</b> <code>!exists(from_ph) && exists(to_ph)</code>,
|
||||
and the file or directory contents and attributes are otherwise unchanged.</p>
|
||||
<p><b>Throws:</b> if <code>!exists(from_ph) || exists(to_ph) || !exists(branch(to_ph))</code></p>
|
||||
<p><b>Rationale:</b> Because <i>rename</i> is logically the same operation as <i>move</i>,
|
||||
there is no need for a separate <i>move</i> function. The choice of the name is
|
||||
inherited from the C Library.</p>
|
||||
<p><b>Note:</b> If <code>branch(from_path)</code> resolves to the same directory
|
||||
as <code>branch(to_ph)</code>, then <code>leaf(from_ph)</code> must not be
|
||||
the same name as <code>leaf(to_ph)</code>, but if the branch directories are
|
||||
different, it doesn't matter if the leaf names are the same.</p>
|
||||
<p><b>Note:</b> Some operating systems with multi-rooted file systems
|
||||
representing different drives, devices, or volumes, do not allow <i>rename</i>
|
||||
operations between roots . Implementations should not take heroic efforts, such
|
||||
as switching to a copy mode, to make an otherwise failing <i>rename </i>succeed
|
||||
across drives, devices, or volumes. </p>
|
||||
</blockquote>
|
||||
<h3><a name="copy_file">copy_file</a></h3>
|
||||
<blockquote>
|
||||
<p><code>void copy_file( const path & from_file_ph, const path &
|
||||
to_file_ph );</code></p>
|
||||
<p><b>Effects:</b> Copies the file represented by <i>from_file_ph</i> to <i>
|
||||
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>
|
||||
<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
|
||||
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
|
||||
protects against another function altering the current working
|
||||
directory (using a native platform function) before the first call to <i>
|
||||
initial_directory()</i>.</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>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
373
doc/path.htm
Normal file
373
doc/path.htm
Normal file
@ -0,0 +1,373 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Language" content="en-us">
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<title>Boost Filesystem path.hpp Header</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF">
|
||||
|
||||
<h1>
|
||||
<img border="0" src="../../../c++boost.gif" align="center" width="277" height="86"><a href="../../../boost/filesystem/path.hpp">boost/filesystem/path.hpp</a></h1>
|
||||
|
||||
<p>
|
||||
<a href="#Introduction">Introduction</a><br>
|
||||
<a href="#Grammar">Grammar for generic path strings</a><br>
|
||||
<a href="#Canonical">Canonical form</a><br>
|
||||
<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>
|
||||
<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>For actual operations on files and directories, see <a href="operations.htm">
|
||||
boost/filesystem/operations.hpp documentation</a>.</p>
|
||||
|
||||
<p>For file I/O stream operations, see <a href="fstream.htm">boost/filesystem/fstream.hpp
|
||||
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>
|
||||
<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
|
||||
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>
|
||||
<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
|
||||
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
|
||||
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
|
||||
format, and supplies constructor and append operations taking such strings as
|
||||
arguments. Because user input or third-party library functions may supply path
|
||||
strings formatted according to operating system specific rules, an additional
|
||||
constructor is provided which takes a system-specific format as an argument.</p>
|
||||
<p>Access functions are provided to retrieve the contents of a object of class
|
||||
<i>path</i> formatted as a portable path string, a directory path string using
|
||||
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>
|
||||
<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>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
|
||||
<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>
|
||||
<p>Although implementation-defined, it is desirable that <i>
|
||||
system-specific-root</i> have a grammar which is distinguishable from other grammar elements,
|
||||
and follow the conventions of the operating system.</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>
|
||||
<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> };
|
||||
|
||||
class path
|
||||
{
|
||||
public:
|
||||
// compiler generates copy constructor,
|
||||
// copy assignment, and destructor
|
||||
|
||||
// constructors:
|
||||
<a href="#constructors">path</a>();
|
||||
<a href="#constructors">path</a>( const std::string & src );
|
||||
<a href="#constructors">path</a>( const char * src );
|
||||
<a href="#constructors">path</a>( const std::string & src, path_format );
|
||||
<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;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
|
||||
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 );
|
||||
|
||||
<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><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,
|
||||
invalid characters, and so on), or because it is a partial path still as yet
|
||||
unfinished by the program. An invalid path will normally be detected at time of
|
||||
use, such as by one of the Filesystem Library's <a href="operations.htm">
|
||||
operations</a> or <a href="fstream.htm">fstream</a> functions.</p>
|
||||
<p><b>Portability Warning:</b> There is no guarantee that a <i>path</i> object
|
||||
represents a path which would be portable to another operating system. A path
|
||||
might be non-portable because it contains names which the operating systems
|
||||
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>
|
||||
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
|
||||
rules, and there is an unambiguous translation between the invalid character and
|
||||
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
|
||||
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>
|
||||
</blockquote>
|
||||
<p>On POSIX or Windows, the output representations would be identical:</p>
|
||||
<blockquote>
|
||||
<pre>generic_path---: foo/bar/data.txt
|
||||
directory_path-: foo/bar/data.txt
|
||||
file_path------: foo/bar/data.txt</pre>
|
||||
</blockquote>
|
||||
<p>But on a hypothetical operating system using OpenVMS format representations,
|
||||
they would each be different:</p>
|
||||
<blockquote>
|
||||
<pre>generic_path---: foo/bar/data.txt
|
||||
directory_path-: [foo.bar.data.txt]
|
||||
file_path------: [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>
|
||||
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><a name="constructors">constructors</a></h3>
|
||||
<blockquote>
|
||||
<pre>path();</pre>
|
||||
<p><b>Effects:</b> Default constructs an object of class <i>path</i>.</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
|
||||
'\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
|
||||
<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>
|
||||
<pre>path( const std::string & src, path_format );
|
||||
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
|
||||
<a href="#Canonical">canonical form</a>.</p>
|
||||
</blockquote>
|
||||
<h3><a name="operator-shift-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>
|
||||
<p><b>Returns:</b> <code>*this</code></p>
|
||||
<p><b>Postcondition:</b> <code>m_name</code> has been reduced to
|
||||
<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
|
||||
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>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
<h3><a name="operator-shift">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
|
||||
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>
|
||||
</blockquote>
|
||||
<h3><a name="is_null">is_null</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>
|
||||
<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
|
||||
relative-path name, a name containing "/", a name "..", and a
|
||||
system-specific-root 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>
|
||||
<blockquote>
|
||||
<pre>const std::string & file_path() 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>
|
||||
</blockquote>
|
||||
<h3><a name="directory_path">directory_path</a></h3>
|
||||
<blockquote>
|
||||
<pre>const std::string & directory_path() 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>
|
||||
</blockquote>
|
||||
<h3><a name="leaf">leaf</a></h3>
|
||||
<blockquote>
|
||||
<pre>const 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>
|
||||
</blockquote>
|
||||
<h3><a name="branch">branch</a></h3>
|
||||
<blockquote>
|
||||
<pre>const path branch() 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>
|
||||
</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>,
|
||||
<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><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><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>
|
||||
<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>
|
||||
</blockquote>
|
||||
<h3><a name="Undocumented non-member functions">Undocumented non-member
|
||||
functions</a></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>
|
||||
<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>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
134
doc/portability_guide.htm
Normal file
134
doc/portability_guide.htm
Normal file
@ -0,0 +1,134 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Language" content="en-us">
|
||||
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
|
||||
<meta name="ProgId" content="FrontPage.Editor.Document">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<title>Portability Guide</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF">
|
||||
|
||||
<h1>
|
||||
<img border="0" src="../../../c++boost.gif" align="center" width="277" height="86">Portability
|
||||
Guide</h1>
|
||||
<h2>Introduction</h2>
|
||||
<p>Like any other C++ program which performs I/O operations, there is no
|
||||
guarantee that a program using the Filesystem Library will be portable between
|
||||
operating systems. The file and directory names in paths present a particularly
|
||||
troublesome portability problem.</p>
|
||||
<p>It is not possible to know in advance if a file or directory name will be
|
||||
valid (and thus portable) for an operating system whose requirements are
|
||||
unknown. There is always the possibility that an operating system could use
|
||||
names which are unusual (number between 17 and 4095, for example) or very
|
||||
limited (maximum of two character names, for example).</p>
|
||||
<p>It is possible, however, to know if a name is valid for a particular
|
||||
operating system. It is also possible to construct names which are very
|
||||
likely to be portable to a large number of modern and legacy operating systems.</p>
|
||||
<p>By providing name validity checking facilities, the Filesystem Library allows
|
||||
programmers to ensure that a given name meets the requirements for specific
|
||||
operating systems, or meets the recommendations for general portability.</p>
|
||||
<p><b>To do:</b> An implementation should be required to provide check functions
|
||||
for the host O/S, and for the portability recommendations. But it isn't
|
||||
possible to require implementors to supply an open ended number of checking
|
||||
functions. It would be helpful if there was a registry to ensure that checking
|
||||
functions for a particular O/S had the same specification regardless of
|
||||
implementor.</p>
|
||||
|
||||
<h2>Limits imposed by specific operating systems</h2>
|
||||
<p>(To be supplied)</p>
|
||||
<table border="1" cellpadding="5">
|
||||
<tr>
|
||||
<td align="center"><b>Operating<br>
|
||||
system</b></td>
|
||||
<td align="center"><b>Check<br>
|
||||
function</b></td>
|
||||
<td align="center"><b>Requirements</b></td>
|
||||
</tr>
|
||||
</table>
|
||||
<h2>File and directory name <a name="recommendations">recommendations</a></h2>
|
||||
|
||||
<p>(Very preliminary draft)</p>
|
||||
|
||||
<table border="1">
|
||||
<tr>
|
||||
<td align="center" valign="top"><strong>Recommendation</strong></td>
|
||||
<td align="center" valign="top"><strong>Check<br>
|
||||
function</strong></td>
|
||||
<td align="center" valign="top"><strong>Rationale</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">Limit file and directory names to the characters A-Z, a-z, 0-9, period, hyphen, and
|
||||
underscore.<br>
|
||||
<br>
|
||||
For even greater portability, don't use hyphens at all.</td>
|
||||
<td valign="top"> </td>
|
||||
<td valign="top">These are the characters specified by the POSIX standard for portable directory and
|
||||
file names, and are also valid for Windows, Mac, and many other modern filesystems.
|
||||
ISO-9660, and possibly some legacy systems, do not permit hyphens at all.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">Do not use periods in directory names. </td>
|
||||
<td valign="top"> </td>
|
||||
<td valign="top">Requirement for Requirement for ISO-9660, OpenVMS native
|
||||
filesystem, and other legacy systems.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">Do not use more that one period in a file name.</td>
|
||||
<td valign="top"> </td>
|
||||
<td valign="top">Requirement for ISO-9660, OpenVMS native filesystem, and
|
||||
other legacy systems. </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">Do not use period, hyphen, or underscore as the first
|
||||
character of a file or directory name.</td>
|
||||
<td valign="top"> </td>
|
||||
<td valign="top">Some operating systems treat have special rules for the
|
||||
first character of names. POSIX, for example.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">Do not assume names are case sensitive. For example, do not expected a directory to be
|
||||
able to hold separate elements named "Foo" and "foo". </td>
|
||||
<td valign="top"> </td>
|
||||
<td valign="top">Some filesystems are case insensitive. For example, Windows
|
||||
NTFS is case preserving in the way it stores names, but case insensitive in
|
||||
searching for names (unless running under the POSIX sub-system, it which
|
||||
case it does case sensitive searches). </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">Do not assume names are case insensitive. For example, do not expect a file
|
||||
created with the name of "Foo" to be open successfully with the name of "foo".</td>
|
||||
<td valign="top"> </td>
|
||||
<td valign="top">Some filesystems are case sensitive. For example, POSIX.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">Limit the length of names and the depth of the directory
|
||||
tree so that the total length of the string returned by generic_path() to
|
||||
255 characters.
|
||||
Note that ISO 9660 level 1 has an explicit directory tree depth limit of 8.</td>
|
||||
<td valign="top"> </td>
|
||||
<td valign="top">Some operating systems place limits on the total path length. For example,
|
||||
Windows 2000 limits paths to 260 characters total length.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">Limit the length of any one name in a path. Pick the specific limit according to
|
||||
the operating systems you wish portability to:<br>
|
||||
Greater than 31 characters: POSIX, Windows, MAC OS X.<br>
|
||||
31 characters: Classic Mac OS<br>
|
||||
8 characters + period + 3 characters: ISO 9660 (CD-ROM)<br>
|
||||
<strong>...</strong></td>
|
||||
<td valign="top"> </td>
|
||||
<td valign="top">Limiting name length can markedly reduce the expressiveness of file names, yet placing
|
||||
only very high limits on lengths inhibits wide portability.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<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>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
63
include/boost/filesystem/exception.hpp
Normal file
63
include/boost/filesystem/exception.hpp
Normal file
@ -0,0 +1,63 @@
|
||||
// boost/filesystem/exception.hpp ------------------------------------------//
|
||||
|
||||
// < ----------------------------------------------------------------------- >
|
||||
// < Copyright © 2001 Dietmar Kühl, All Rights Reserved >
|
||||
// < >
|
||||
// < Permission to use, copy, modify, distribute and sell this >
|
||||
// < software for any purpose is hereby granted without fee, provided >
|
||||
// < that the above copyright notice appears in all copies and that >
|
||||
// < both that copyright notice and this permission notice appear in >
|
||||
// < supporting documentation. Dietmar Kühl makes no representations about >
|
||||
// < the suitability of this software for any purpose. It is provided >
|
||||
// < "as is" without express or implied warranty. >
|
||||
// < ----------------------------------------------------------------------- >
|
||||
|
||||
// Original author: Dietmar Kühl. Revised by Beman Dawes.
|
||||
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#ifndef BOOST_FILESYSTEM_EXCEPTION_HPP
|
||||
#define BOOST_FILESYSTEM_EXCEPTION_HPP
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
enum error_type { system_error };
|
||||
|
||||
class filesystem_error:
|
||||
public std::runtime_error
|
||||
{
|
||||
public:
|
||||
|
||||
explicit filesystem_error( std::string const& msg );
|
||||
// Effects: : std::runtime_error(implementation-defined),
|
||||
// m_msg(msg), m_err(0)
|
||||
|
||||
explicit filesystem_error( std::string const& msg, error_type );
|
||||
// Effects: : std::runtime_error(implementation-defined),
|
||||
// m_msg(msg), m_err(value), where value is appropriate
|
||||
// for the operating system (for example, GetLastError() on Windows,
|
||||
// errno on POSIX)
|
||||
|
||||
~filesystem_error() throw();
|
||||
char const* what() const throw();
|
||||
int error() const { return m_err; }
|
||||
// Note: a value of 0 implies an internal (rather than system) error
|
||||
|
||||
private:
|
||||
mutable std::string m_msg;
|
||||
mutable int m_err;
|
||||
};
|
||||
|
||||
} // namespace filesystem
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_FILESYSTEM_EXCEPTION_HPP
|
116
include/boost/filesystem/fstream.hpp
Normal file
116
include/boost/filesystem/fstream.hpp
Normal file
@ -0,0 +1,116 @@
|
||||
// boost/filesystem/fstream.hpp --------------------------------------------//
|
||||
|
||||
// (C) Copyright 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 for most recent version including documentation.
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#ifndef BOOST_FILESYSTEM_FSTREAM_HPP
|
||||
#define BOOST_FILESYSTEM_FSTREAM_HPP
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include <iosfwd>
|
||||
#include <fstream>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
template < class charT, class traits = std::char_traits<charT> >
|
||||
class basic_filebuf : public std::basic_filebuf<charT,traits>
|
||||
{
|
||||
public:
|
||||
virtual ~basic_filebuf() {}
|
||||
|
||||
std::basic_filebuf<charT,traits> * open( const path & file_ph,
|
||||
std::ios_base::openmode mode )
|
||||
{
|
||||
return std::basic_filebuf<charT,traits>::open(
|
||||
file_ph.file_path().c_str(), mode );
|
||||
}
|
||||
};
|
||||
|
||||
typedef basic_filebuf<char> filebuf;
|
||||
# ifndef BOOST_NO_STD_WSTRING
|
||||
typedef basic_filebuf<wchar_t> wfilebuf;
|
||||
# endif
|
||||
|
||||
template < class charT, class traits = std::char_traits<charT> >
|
||||
class basic_ifstream : public std::basic_ifstream<charT,traits>
|
||||
{
|
||||
public:
|
||||
basic_ifstream() {}
|
||||
explicit basic_ifstream( const path & file_ph,
|
||||
std::ios_base::openmode mode = std::ios_base::in )
|
||||
: std::basic_ifstream<charT,traits>(
|
||||
file_ph.file_path().c_str(), mode ) {}
|
||||
virtual ~basic_ifstream() {}
|
||||
void open( const path & file_ph,
|
||||
std::ios_base::openmode mode = std::ios_base::in )
|
||||
{
|
||||
std::basic_ifstream<charT,traits>::open(
|
||||
file_ph.file_path().c_str(), mode );
|
||||
}
|
||||
};
|
||||
|
||||
typedef basic_ifstream<char> ifstream;
|
||||
# ifndef BOOST_NO_STD_WSTRING
|
||||
typedef basic_ifstream<wchar_t> wifstream;
|
||||
# endif
|
||||
|
||||
template < class charT, class traits = std::char_traits<charT> >
|
||||
class basic_ofstream : public std::basic_ofstream<charT,traits>
|
||||
{
|
||||
public:
|
||||
basic_ofstream() {}
|
||||
explicit basic_ofstream( const path & file_ph,
|
||||
std::ios_base::openmode mode = std::ios_base::out )
|
||||
: std::basic_ofstream<charT,traits>(
|
||||
file_ph.file_path().c_str(), mode ) {}
|
||||
virtual ~basic_ofstream() {}
|
||||
void open( const path & file_ph,
|
||||
std::ios_base::openmode mode = std::ios_base::out )
|
||||
{
|
||||
std::basic_ofstream<charT,traits>::open(
|
||||
file_ph.file_path().c_str(), mode );
|
||||
}
|
||||
};
|
||||
|
||||
typedef basic_ofstream<char> ofstream;
|
||||
# ifndef BOOST_NO_STD_WSTRING
|
||||
typedef basic_ofstream<wchar_t> wofstream;
|
||||
# endif
|
||||
|
||||
template < class charT, class traits = std::char_traits<charT> >
|
||||
class basic_fstream : public std::basic_fstream<charT,traits>
|
||||
{
|
||||
public:
|
||||
basic_fstream() {}
|
||||
explicit basic_fstream( const path & file_ph,
|
||||
std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out )
|
||||
: std::basic_fstream<charT,traits>(
|
||||
file_ph.file_path().c_str(), mode ) {}
|
||||
virtual ~basic_fstream() {}
|
||||
void open( const path & file_ph,
|
||||
std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out )
|
||||
{
|
||||
std::basic_fstream<charT,traits>::open(
|
||||
file_ph.file_path().c_str(), mode );
|
||||
}
|
||||
};
|
||||
|
||||
typedef basic_fstream<char> fstream;
|
||||
# ifndef BOOST_NO_STD_WSTRING
|
||||
typedef basic_fstream<wchar_t> wfstream;
|
||||
# endif
|
||||
} // namespace filesystem
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_FILESYSTEM_FSTREAM_HPP
|
||||
|
129
include/boost/filesystem/operations.hpp
Normal file
129
include/boost/filesystem/operations.hpp
Normal file
@ -0,0 +1,129 @@
|
||||
// boost/filesystem/directory.hpp ------------------------------------------//
|
||||
|
||||
// < ----------------------------------------------------------------------- >
|
||||
// < Copyright © 2002 Beman Dawes. >
|
||||
// < Copyright © 2002 Jan Langer. >
|
||||
// < Copyright © 2001 Dietmar Kühl, All Rights Reserved >
|
||||
// < >
|
||||
// < Permission to use, copy, modify, distribute and sell this >
|
||||
// < software for any purpose is hereby granted without fee, provided >
|
||||
// < that the above copyright notice appears in all copies and that >
|
||||
// < both that copyright notice and this permission notice appear in >
|
||||
// < supporting documentation. The authors make no representations about >
|
||||
// < the suitability of this software for any purpose. It is provided >
|
||||
// < "as is" without express or implied warranty. >
|
||||
// < ----------------------------------------------------------------------- >
|
||||
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#ifndef BOOST_FILESYSTEM_DIRECTORY_HPP
|
||||
#define BOOST_FILESYSTEM_DIRECTORY_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/smart_ptr.hpp>
|
||||
#include <boost/iterator_adaptors.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
|
||||
// query functions ---------------------------------------------------------//
|
||||
|
||||
bool exists( const path & ph );
|
||||
|
||||
bool is_directory( const path & ph );
|
||||
|
||||
// VC++ 7.0 and earlier has a serious namespace bug that causes a clash
|
||||
// between boost::filesystem::is_empty and the unrelated type trait
|
||||
// boost::is_empty. The workaround for those who must use broken versions
|
||||
// of VC++ is to use the function _is_empty. All others should use the
|
||||
// correct is_empty name.
|
||||
bool _is_empty( const path & ph ); // deprecated
|
||||
|
||||
# if !defined( BOOST_MSVC ) || BOOST_MSVC > 1300
|
||||
inline bool is_empty( const path & ph ) { return _is_empty( ph ); }
|
||||
# endif
|
||||
|
||||
// operations --------------------------------------------------------------//
|
||||
|
||||
void create_directory( const path & directory_ph );
|
||||
|
||||
void remove( const path & ph );
|
||||
|
||||
void rename( const path & from_path,
|
||||
const path & to_path );
|
||||
|
||||
unsigned long remove_all( const path & ph );
|
||||
|
||||
void copy_file( const path & from_file_ph,
|
||||
const path & to_file_ph );
|
||||
|
||||
const path & initial_directory();
|
||||
|
||||
// directory_iterator details ----------------------------------------------//
|
||||
|
||||
namespace detail
|
||||
{
|
||||
const char * implementation_name();
|
||||
|
||||
class directory_iterator_imp;
|
||||
|
||||
struct directory_iterator_internals
|
||||
{
|
||||
typedef boost::shared_ptr< detail::directory_iterator_imp > dii_ptr;
|
||||
dii_ptr imp;
|
||||
|
||||
const path & deref() const;
|
||||
void inc();
|
||||
};
|
||||
|
||||
struct dii_policies : public default_iterator_policies
|
||||
{
|
||||
|
||||
template <class IteratorAdaptor>
|
||||
typename IteratorAdaptor::reference
|
||||
dereference(const IteratorAdaptor& x) const
|
||||
{ return x.base().deref(); }
|
||||
|
||||
template <class IteratorAdaptor>
|
||||
void increment(IteratorAdaptor& x)
|
||||
{ x.base().inc(); }
|
||||
|
||||
template <class IteratorAdaptor1, class IteratorAdaptor2>
|
||||
bool equal(const IteratorAdaptor1& x, const IteratorAdaptor2& y) const
|
||||
{ return x.base().imp == y.base().imp; }
|
||||
};
|
||||
}
|
||||
|
||||
// directory_iterator ------------------------------------------------------//
|
||||
|
||||
class directory_iterator
|
||||
: public boost::iterator_adaptor<
|
||||
// because directory_iterator is an InputIterator, shallow copy-
|
||||
// semantics are required, and shared_ptr provides that.
|
||||
detail::directory_iterator_internals,
|
||||
detail::dii_policies,
|
||||
path, const path &, const path *,
|
||||
std::input_iterator_tag, std::ptrdiff_t >
|
||||
{
|
||||
public:
|
||||
directory_iterator(); // creates the "end" iterator
|
||||
explicit directory_iterator( const path & directory_path );
|
||||
|
||||
// workaround iterator_adaptor / compiler interactions
|
||||
const boost::filesystem::path * operator->() const
|
||||
{ return &base().deref(); }
|
||||
};
|
||||
|
||||
} // namespace filesystem
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_FILESYSTEM_DIRECTORY_HPP
|
198
include/boost/filesystem/path.hpp
Normal file
198
include/boost/filesystem/path.hpp
Normal file
@ -0,0 +1,198 @@
|
||||
// boost/filesystem/path.hpp -----------------------------------------------//
|
||||
|
||||
// (C) Copyright 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 for most recent version including documentation.
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#ifndef BOOST_FILESYSTEM_PATH_HPP
|
||||
#define BOOST_FILESYSTEM_PATH_HPP
|
||||
|
||||
#include <boost/iterator_adaptors.hpp>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
class path;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct path_itr_imp
|
||||
{
|
||||
std::string name; // cache current element.
|
||||
const path * path_ptr; // path being iterated over.
|
||||
std::string::size_type pos; // position of name in
|
||||
// path_ptr->generic_path(). The
|
||||
// end() iterator is indicated by
|
||||
// pos == path_ptr->generic_path().size()
|
||||
|
||||
const std::string & operator*() const { return name; }
|
||||
void operator++();
|
||||
void operator--();
|
||||
bool operator==( const path_itr_imp & rhs ) const
|
||||
{ return path_ptr == rhs.path_ptr && pos == rhs.pos; }
|
||||
};
|
||||
}
|
||||
|
||||
enum path_format { system_specific }; // ugly enough to discourage use
|
||||
// except when actually needed
|
||||
|
||||
// path -------------------------------------------------------------------//
|
||||
|
||||
class path
|
||||
{
|
||||
public:
|
||||
// compiler generates copy constructor, copy assignment, and destructor
|
||||
|
||||
path(){}
|
||||
|
||||
path( const std::string & src );
|
||||
path( const char * src );
|
||||
|
||||
path( const std::string & src, path_format );
|
||||
path( const char * src, path_format );
|
||||
|
||||
// append operations:
|
||||
path & operator <<=( const path & rhs );
|
||||
const path operator << ( const path & rhs ) const
|
||||
{ return path( *this ) <<= rhs; }
|
||||
|
||||
// query functions:
|
||||
bool is_null() const { return m_path.size() == 0; }
|
||||
|
||||
const std::string & generic_path() const { return m_path; }
|
||||
const std::string & file_path() const { return m_path; } // native format
|
||||
const std::string & directory_path() const { return m_path; } // ditto
|
||||
|
||||
const std::string leaf() const;
|
||||
const path branch() const;
|
||||
|
||||
// iteration over the names in the path:
|
||||
typedef boost::iterator_adaptor<
|
||||
detail::path_itr_imp,
|
||||
boost::default_iterator_policies,
|
||||
std::string,
|
||||
const std::string &,
|
||||
const std::string *,
|
||||
std::bidirectional_iterator_tag,
|
||||
std::ptrdiff_t
|
||||
> iterator;
|
||||
|
||||
const iterator begin() const;
|
||||
const iterator end() const
|
||||
{
|
||||
iterator itr;
|
||||
itr.base().path_ptr = this;
|
||||
itr.base().pos = m_path.size();
|
||||
return itr;
|
||||
}
|
||||
|
||||
private:
|
||||
// Note: This is an implementation for POSIX and Windows, where there
|
||||
// are only minor differences between generic and system-specific
|
||||
// constructor input formats. Private members might be quite different
|
||||
// in other implementations, particularly where there were wide
|
||||
// differences between generic and system-specific argument formats,
|
||||
// or between file_path() and directory_path() formats.
|
||||
|
||||
std::string m_path;
|
||||
|
||||
friend class directory_iterator;
|
||||
friend struct boost::filesystem::detail::path_itr_imp;
|
||||
|
||||
enum source_context { generic, platform, nocheck };
|
||||
|
||||
void m_path_append( const std::string & src,
|
||||
source_context context = generic );
|
||||
|
||||
public: // should be private, but friend functions don't work for me
|
||||
void m_replace_leaf( const char * new_leaf );
|
||||
};
|
||||
|
||||
// path non-member functions ---------------------------------------------//
|
||||
|
||||
inline const path operator << ( const char * lhs, const path & rhs )
|
||||
{ return path( lhs ) <<= rhs; }
|
||||
|
||||
inline const path operator << ( const std::string & lhs, const path & rhs )
|
||||
{ return path( lhs ) <<= rhs; }
|
||||
|
||||
// error checking --------------------------------------------------------//
|
||||
|
||||
// TODO: write a program that probes valid file and directory names. Ask
|
||||
// Boost people to report results from many operating systems. Use results
|
||||
// to adjust generic_name().
|
||||
|
||||
// generic_name() is extremely permissive; its intent is not to ensure
|
||||
// general portablity, but rather to detect names so trouble-prone that
|
||||
// they likely represent coding errors or gross misconceptions.
|
||||
//
|
||||
// Any characters are allowed except:
|
||||
//
|
||||
// Those characters < ' ', including '\0'. These are the so-called
|
||||
// control characters, in both ASCII (and its decendents) and EBCDIC.
|
||||
// Hard to imagine how these could be useful in a generic path name.
|
||||
//
|
||||
// < > : " / \ | * ? These have special meaning to enough operating
|
||||
// systems that use in a generic name would be a serious problem.
|
||||
//
|
||||
// The names "." and ".." are not allowed.
|
||||
// An empty name (null string) is not allowed.
|
||||
// Names beginning or ending with spaces are not allowed.
|
||||
//
|
||||
bool generic_name( const std::string & name );
|
||||
|
||||
// posix_name() is based on POSIX (IEEE Std 1003.1-2001)
|
||||
// "Portable Filename Character Set" rules.
|
||||
// http://www.opengroup.org/onlinepubs/007904975/basedefs/xbd_chap03.html
|
||||
//
|
||||
// That character set only allows 0-9, a-z, A-Z, '.', '_', and '-'.
|
||||
// Note that such names are also portable to other popular operating
|
||||
// systems, such as Windows.
|
||||
//
|
||||
bool posix_name( const std::string & name );
|
||||
|
||||
const path & check_posix_leaf( const path & ph );
|
||||
// Throws: if !posix_name( ph.leaf() )
|
||||
// Returns: ph
|
||||
// Note: Although useful in its own right, check_posix_leaf() also serves
|
||||
// as an example. A user might provide similar functions; behavior might
|
||||
// be to assert or warn rather than throw. A user provided function
|
||||
// could also check the entire path instead of just the leaf; a leaf
|
||||
// check is often, but not always, the required behavior.
|
||||
// Rationale: For the "const path &" rather than "void" return is to
|
||||
// allow (and encourage portability checking) uses like:
|
||||
// create_directory( check_posix_leaf( "foo" ) );
|
||||
// While there is some chance of misuse (by passing through a reference
|
||||
// to a temporary), the benefits outweigh the costs.
|
||||
|
||||
// For Boost, we often tighten name restrictions for maximum portability:
|
||||
//
|
||||
// * The portable POSIX character restrictions, plus
|
||||
// * Maximum name length 31 characters (for Classic Mac OS).
|
||||
// * Lowercase only (so code written on case-insensitive platforms like
|
||||
// Windows works properly when used on case-sensitive systems like
|
||||
// POSIX.
|
||||
// * Directory names do not contain '.', as this is not a valid character
|
||||
// for directory names on some systems.
|
||||
//
|
||||
// TODO: provide some check_boost_xxx functions once error handling
|
||||
// approach ratified.
|
||||
|
||||
bool boost_file_name( const std::string & name );
|
||||
bool boost_directory_name( const std::string & name );
|
||||
|
||||
} // namespace filesystem
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_FILESYSTEM_PATH_HPP
|
116
include/boost/filesystem/recursive_directory_iterator.hpp
Normal file
116
include/boost/filesystem/recursive_directory_iterator.hpp
Normal file
@ -0,0 +1,116 @@
|
||||
// boost/filesystem/recursive_directory_iterator.hpp -----------------------//
|
||||
|
||||
// (C) Copyright 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 for most recent version including documentation.
|
||||
|
||||
#ifndef BOOST_FILESYSTEM_RECURSIVE_DIRECTORY_ITERATOR_HPP
|
||||
#define BOOST_FILESYSTEM_RECURSIVE_DIRECTORY_ITERATOR_HPP
|
||||
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/iterator_adaptors.hpp>
|
||||
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
//#include <iostream>
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
const directory_iterator end_itr;
|
||||
|
||||
template< typename Predicate >
|
||||
struct rdi_imp
|
||||
{
|
||||
std::stack< directory_iterator, std::vector<directory_iterator> >
|
||||
stac;
|
||||
Predicate pred;
|
||||
|
||||
rdi_imp( const path & pth, Predicate pred )
|
||||
: pred(pred)
|
||||
{
|
||||
stac.push( directory_iterator( pth ) );
|
||||
while ( stac.top() != end_itr
|
||||
&& !pred( *stac.top() ) ) ++stac.top();
|
||||
}
|
||||
|
||||
rdi_imp()
|
||||
: pred( Predicate() )
|
||||
{
|
||||
stac.push( directory_iterator() );
|
||||
}
|
||||
|
||||
void increment()
|
||||
{
|
||||
if ( is_directory( *stac.top() ) )
|
||||
stac.push( directory_iterator( *stac.top() ) );
|
||||
else ++stac.top();
|
||||
for (;;) // 'til end or pred true
|
||||
{
|
||||
while ( stac.top() != end_itr && !pred( *stac.top() ) )
|
||||
{ ++stac.top(); }
|
||||
if ( stac.top() != end_itr || stac.size() == 1 ) return;
|
||||
stac.pop();
|
||||
++stac.top();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct rdi_policies : public default_iterator_policies
|
||||
{
|
||||
|
||||
template <class IteratorAdaptor>
|
||||
typename IteratorAdaptor::reference dereference(const IteratorAdaptor& x) const
|
||||
{
|
||||
return *x.base()->stac.top();
|
||||
}
|
||||
|
||||
template <class IteratorAdaptor>
|
||||
void increment(IteratorAdaptor& x) { x.base()->increment(); }
|
||||
|
||||
template <class IteratorAdaptor1, class IteratorAdaptor2>
|
||||
bool equal(const IteratorAdaptor1& x, const IteratorAdaptor2& y) const
|
||||
{
|
||||
return x.base()->stac.top() == y.base()->stac.top();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template< typename Predicate >
|
||||
class recursive_directory_iterator
|
||||
: public boost::iterator_adaptor<
|
||||
boost::shared_ptr< detail::rdi_imp< Predicate > >,
|
||||
detail::rdi_policies,
|
||||
boost::filesystem::path,
|
||||
const boost::filesystem::path &,
|
||||
const boost::filesystem::path *,
|
||||
std::input_iterator_tag,
|
||||
std::ptrdiff_t >
|
||||
{
|
||||
public:
|
||||
recursive_directory_iterator( const path & pth, Predicate pred )
|
||||
{
|
||||
this->base().reset( new detail::rdi_imp<Predicate>( pth, pred ) );
|
||||
}
|
||||
recursive_directory_iterator() // the past-the-end iterator
|
||||
{
|
||||
this->base().reset( new detail::rdi_imp<Predicate> );
|
||||
}
|
||||
|
||||
// workaround iterator_adaptor / compiler interactions
|
||||
const boost::filesystem::path * operator->() const
|
||||
{ return &*this->base()->stac.top(); }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BOOST_FILESYSTEM_RECURSIVE_DIRECTORY_ITERATOR_HPP
|
9
index.html
Normal file
9
index.html
Normal file
@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; URL=doc/index.htm">
|
||||
</head>
|
||||
<body>
|
||||
Automatic redirection failed, please go to
|
||||
<a href="doc/index.htm">doc/index.htm</a>.
|
||||
</body>
|
||||
</html>
|
104
src/exception.cpp
Normal file
104
src/exception.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
// Exception implementation file -------------------------------------------//
|
||||
|
||||
// < ----------------------------------------------------------------------- >
|
||||
// < Copyright © 2001 Dietmar Kühl, All Rights Reserved >
|
||||
// < >
|
||||
// < Permission to use, copy, modify, distribute and sell this >
|
||||
// < software for any purpose is hereby granted without fee, provided >
|
||||
// < that the above copyright notice appears in all copies and that >
|
||||
// < both that copyright notice and this permission notice appear in >
|
||||
// < supporting documentation. Dietmar Kühl makes no representations about >
|
||||
// < the suitability of this software for any purpose. It is provided >
|
||||
// < "as is" without express or implied warranty. >
|
||||
// < ----------------------------------------------------------------------- >
|
||||
|
||||
// Original author: Dietmar Kühl. Revised by Beman Dawes.
|
||||
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/filesystem/exception.hpp>
|
||||
|
||||
#include <cerrno>
|
||||
#include <string>
|
||||
|
||||
# ifdef BOOST_NO_STDC_NAMESPACE
|
||||
namespace std { using ::strerror; }
|
||||
# endif
|
||||
|
||||
// BOOST_POSIX or BOOST_WINDOWS specify which API to use, not the current
|
||||
// operating system. GCC defaults to BOOST_POSIX; it doesn't predefine _WIN32.
|
||||
|
||||
# if !defined( BOOST_WINDOWS ) && !defined( BOOST_POSIX )
|
||||
# if defined(_WIN32)
|
||||
# define BOOST_WINDOWS
|
||||
# else
|
||||
# define BOOST_POSIX
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if defined( BOOST_WINDOWS )
|
||||
# include "windows.h"
|
||||
# endif
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
|
||||
filesystem_error::filesystem_error( std::string const& msg ):
|
||||
std::runtime_error("filesystem error"),
|
||||
m_msg(msg),
|
||||
m_err(0)
|
||||
{
|
||||
}
|
||||
|
||||
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() 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
|
||||
|
424
src/operations_posix_windows.cpp
Normal file
424
src/operations_posix_windows.cpp
Normal file
@ -0,0 +1,424 @@
|
||||
// directory_posix_windows.cpp ---------------------------------------------//
|
||||
|
||||
// < ----------------------------------------------------------------------- >
|
||||
// < Copyright © 2002 Beman Dawes. >
|
||||
// < Copyright © 2001 Dietmar Kühl, All Rights Reserved >
|
||||
// < >
|
||||
// < Permission to use, copy, modify, distribute and sell this >
|
||||
// < software for any purpose is hereby granted without fee, provided >
|
||||
// < that the above copyright notice appears in all copies and that >
|
||||
// < both that copyright notice and this permission notice appear in >
|
||||
// < supporting documentation. The authors make no representations about >
|
||||
// < the suitability of this software for any purpose. It is provided >
|
||||
// < "as is" without expressed or implied warranty. >
|
||||
// < ----------------------------------------------------------------------- >
|
||||
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
|
||||
// The point of this implementation is to prove the interface. There is no
|
||||
// claim the implementation is efficient, follows good coding practice, etc.
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/filesystem/exception.hpp>
|
||||
//#include <iostream>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
// BOOST_POSIX or BOOST_WINDOWS specify which API to use, not the current
|
||||
// operating system. GCC defaults to BOOST_POSIX; it doesn't predefine _WIN32.
|
||||
|
||||
# if defined(BOOST_WINDOWS) || (!defined(BOOST_POSIX) && defined(_WIN32))
|
||||
# include "windows.h"
|
||||
# else
|
||||
# define BOOST_POSIX
|
||||
# include "sys/stat.h"
|
||||
# include "dirent.h"
|
||||
# include "unistd.h"
|
||||
# include "fcntl.h"
|
||||
# endif
|
||||
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <cerrno>
|
||||
#include <cassert>
|
||||
|
||||
// helpers -----------------------------------------------------------------//
|
||||
|
||||
namespace
|
||||
{
|
||||
#ifdef BOOST_POSIX
|
||||
|
||||
# define BOOST_HANDLE DIR *
|
||||
# define BOOST_INVALID_HANDLE_VALUE 0
|
||||
# define BOOST_SYSTEM_DIRECTORY_TYPE struct dirent *
|
||||
|
||||
inline const char * find_first_file( const char * dir,
|
||||
BOOST_HANDLE & handle, BOOST_SYSTEM_DIRECTORY_TYPE & )
|
||||
// Returns: 0 if error, otherwise name
|
||||
{
|
||||
const char * dummy_first_name = ".";
|
||||
return ( (handle = ::opendir( dir ))
|
||||
== BOOST_INVALID_HANDLE_VALUE ) ? 0 : dummy_first_name;
|
||||
}
|
||||
|
||||
inline void find_close( BOOST_HANDLE handle )
|
||||
{
|
||||
assert( handle != BOOST_INVALID_HANDLE_VALUE );
|
||||
::closedir( handle );
|
||||
}
|
||||
|
||||
inline const char * find_next_file(
|
||||
BOOST_HANDLE handle, BOOST_SYSTEM_DIRECTORY_TYPE & )
|
||||
// Returns: if EOF 0, otherwise name
|
||||
// Throws: if system reports error
|
||||
{
|
||||
|
||||
// TODO: use readdir_r() if available, so code is multi-thread safe.
|
||||
// Fly-in-ointment: not all platforms support readdir_r().
|
||||
|
||||
struct dirent * dp;
|
||||
errno = 0;
|
||||
if ( (dp = ::readdir( handle )) == 0 )
|
||||
{
|
||||
if ( errno != 0 )
|
||||
{
|
||||
throw fs::filesystem_error( "directory_iterator ++() failure" );
|
||||
}
|
||||
else { return 0; } // end reached
|
||||
}
|
||||
return dp->d_name;
|
||||
}
|
||||
#else // BOOST_WINDOWS
|
||||
|
||||
# define BOOST_HANDLE HANDLE
|
||||
# define BOOST_INVALID_HANDLE_VALUE INVALID_HANDLE_VALUE
|
||||
# define BOOST_SYSTEM_DIRECTORY_TYPE WIN32_FIND_DATA
|
||||
|
||||
inline const char * find_first_file( const char * dir,
|
||||
BOOST_HANDLE & handle, BOOST_SYSTEM_DIRECTORY_TYPE & data )
|
||||
// Returns: 0 if error, otherwise name
|
||||
{
|
||||
std::string dirpath( std::string(dir) + "/*" );
|
||||
return ( (handle = ::FindFirstFile( dirpath.c_str(), &data ))
|
||||
== BOOST_INVALID_HANDLE_VALUE ) ? 0 : data.cFileName;
|
||||
}
|
||||
|
||||
inline void find_close( BOOST_HANDLE handle )
|
||||
{
|
||||
assert( handle != BOOST_INVALID_HANDLE_VALUE );
|
||||
::FindClose( handle );
|
||||
}
|
||||
|
||||
inline const char * find_next_file(
|
||||
BOOST_HANDLE handle, BOOST_SYSTEM_DIRECTORY_TYPE & data )
|
||||
// Returns: 0 if EOF, otherwise name
|
||||
// Throws: if system reports error
|
||||
{
|
||||
if ( ::FindNextFile( handle, &data ) == 0 )
|
||||
{
|
||||
if ( ::GetLastError() != ERROR_NO_MORE_FILES )
|
||||
{
|
||||
throw fs::filesystem_error(
|
||||
"directory_iterator ++() failure", fs::system_error );
|
||||
}
|
||||
else { return 0; } // end reached
|
||||
}
|
||||
return data.cFileName;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
fs::directory_iterator end_itr;
|
||||
|
||||
bool is_empty_directory( const fs::path & dir_path )
|
||||
{
|
||||
return fs::directory_iterator(dir_path) == end_itr;
|
||||
}
|
||||
|
||||
unsigned long remove_all_aux( const fs::path & ph )
|
||||
{
|
||||
unsigned long count = 1;
|
||||
if ( fs::is_directory( ph ) )
|
||||
{
|
||||
for ( boost::filesystem::directory_iterator itr( ph );
|
||||
itr != end_itr; ++itr )
|
||||
{
|
||||
count += remove_all_aux( *itr );
|
||||
}
|
||||
}
|
||||
fs::remove( ph );
|
||||
return count;
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
#ifdef BOOST_POSIX
|
||||
const char * implementation_name() { return "POSIX"; }
|
||||
#else
|
||||
const char * implementation_name() { return "Windows"; }
|
||||
#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
|
||||
|
||||
// directory_iterator implementation ---------------------------------------//
|
||||
|
||||
// default ctor creates the "end" iterator (by letting base default to 0)
|
||||
directory_iterator::directory_iterator() {}
|
||||
|
||||
directory_iterator::directory_iterator( const path & dir_path )
|
||||
{
|
||||
base().imp.reset( new detail::directory_iterator_imp );
|
||||
BOOST_SYSTEM_DIRECTORY_TYPE scratch;
|
||||
const char * name;
|
||||
if ( dir_path.is_null() )
|
||||
base().imp->handle = BOOST_INVALID_HANDLE_VALUE;
|
||||
else
|
||||
name = find_first_file( dir_path.directory_path().c_str(),
|
||||
base().imp->handle, scratch ); // sets handle
|
||||
|
||||
if ( base().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() == ".." ) )
|
||||
{ operator++(); }
|
||||
}
|
||||
else
|
||||
{
|
||||
throw filesystem_error( std::string(
|
||||
"directory_iterator constructor failure: " )
|
||||
+ dir_path.directory_path().c_str(), system_error );
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
path const & directory_iterator_internals::deref() const
|
||||
{
|
||||
assert( imp.get() ); // fails if dereference end iterator
|
||||
return imp->entry_path;
|
||||
}
|
||||
|
||||
void directory_iterator_internals::inc()
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// free functions ----------------------------------------------------------//
|
||||
|
||||
bool exists( const path & ph )
|
||||
{
|
||||
# ifdef BOOST_POSIX
|
||||
struct stat path_stat;
|
||||
return ::stat( ph.file_path().c_str(), &path_stat ) == 0;
|
||||
# else
|
||||
return ::GetFileAttributes( ph.file_path().c_str() ) != 0xFFFFFFFF;
|
||||
# endif
|
||||
}
|
||||
|
||||
bool is_directory( const path & ph )
|
||||
{
|
||||
# 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 );
|
||||
return S_ISDIR( path_stat.st_mode );
|
||||
# else
|
||||
DWORD attributes = ::GetFileAttributes( ph.directory_path().c_str() );
|
||||
if ( attributes == 0xFFFFFFFF )
|
||||
throw filesystem_error( std::string("is_directory(): ")
|
||||
+ ph.directory_path().c_str(), system_error );
|
||||
return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
# endif
|
||||
}
|
||||
|
||||
bool _is_empty( const path & ph )
|
||||
{
|
||||
# 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 );
|
||||
|
||||
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(),
|
||||
::GetFileExInfoStandard, &fad ) )
|
||||
throw filesystem_error( std::string("is_empty(): ")
|
||||
+ ph.file_path().c_str(), system_error );
|
||||
|
||||
return ( fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
|
||||
? is_empty_directory( ph )
|
||||
:( !fad.nFileSizeHigh && !fad.nFileSizeLow );
|
||||
# endif
|
||||
}
|
||||
|
||||
void create_directory( const path & dir_path )
|
||||
{
|
||||
# ifdef BOOST_POSIX
|
||||
if ( ::mkdir( dir_path.directory_path().c_str(),
|
||||
S_IRWXU|S_IRWXG|S_IRWXO ) != 0 )
|
||||
# else
|
||||
if ( !::CreateDirectory( dir_path.directory_path().c_str(), 0 ) )
|
||||
# endif
|
||||
throw filesystem_error( std::string("create_directory(): ")
|
||||
+ dir_path.directory_path().c_str(), system_error );
|
||||
}
|
||||
|
||||
void remove( const path & ph )
|
||||
{
|
||||
if ( exists( ph ) )
|
||||
{
|
||||
if ( is_directory( ph ) )
|
||||
{
|
||||
# ifdef BOOST_POSIX
|
||||
if ( ::rmdir( ph.file_path().c_str() ) != 0 )
|
||||
# else
|
||||
if ( !::RemoveDirectory( ph.file_path().c_str() ) )
|
||||
# endif
|
||||
throw fs::filesystem_error( std::string("remove() on: ")
|
||||
+ ph.file_path().c_str(), system_error );
|
||||
}
|
||||
else
|
||||
{
|
||||
# ifdef BOOST_POSIX
|
||||
if ( ::remove( ph.file_path().c_str() ) != 0 )
|
||||
# else
|
||||
if ( !::DeleteFile( ph.file_path().c_str() ) )
|
||||
# endif
|
||||
throw fs::filesystem_error( std::string("remove() on: ")
|
||||
+ ph.file_path().c_str(), system_error );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long remove_all( const path & ph )
|
||||
{
|
||||
return exists( ph ) ? remove_all_aux( ph ) : 0;
|
||||
}
|
||||
|
||||
void rename( const path & old_path,
|
||||
const path & new_path )
|
||||
{
|
||||
# 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 )
|
||||
# else
|
||||
if ( !::MoveFile( old_path.file_path().c_str(), new_path.file_path().c_str() ) )
|
||||
# endif
|
||||
throw filesystem_error( std::string("move_file(): ")
|
||||
+ old_path.file_path().c_str() + ", " + new_path.file_path().c_str(), system_error );
|
||||
}
|
||||
|
||||
void copy_file( const path & from_file_ph,
|
||||
const path & to_file_ph )
|
||||
{
|
||||
# ifdef BOOST_POSIX
|
||||
// TODO: Ask POSIX experts if this is the best way to copy a file
|
||||
|
||||
const std::size_t buf_sz = 32768;
|
||||
boost::scoped_array<char> buf( new char [buf_sz] );
|
||||
int infile, outfile;
|
||||
|
||||
if ( (infile = ::open( from_file_ph.file_path().c_str(),
|
||||
O_RDONLY )) < 0
|
||||
|| (outfile = ::open( to_file_ph.file_path().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 );
|
||||
}
|
||||
|
||||
ssize_t sz;
|
||||
while ( (sz = ::read( infile, buf.get(), buf_sz )) > 0
|
||||
&& (sz = ::write( outfile, buf.get(), sz )) > 0 ) {}
|
||||
|
||||
::close( infile );
|
||||
::close( outfile );
|
||||
|
||||
if ( sz != 0 )
|
||||
# else
|
||||
if ( !::CopyFile( from_file_ph.file_path().c_str(),
|
||||
to_file_ph.file_path().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 );
|
||||
}
|
||||
|
||||
const path & initial_directory()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
} // namespace filesystem
|
||||
} // namespace boost
|
||||
|
396
src/path_posix_windows.cpp
Normal file
396
src/path_posix_windows.cpp
Normal file
@ -0,0 +1,396 @@
|
||||
// path implementation -----------------------------------------------------//
|
||||
|
||||
// (C) Copyright 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 for most recent version including documentation.
|
||||
|
||||
|
||||
//****************************************************************************//
|
||||
|
||||
// WARNING: This code was hacked time and time again as different library
|
||||
// designs were tried. Thus portions may be residue from the earlier
|
||||
// experiments, and be totally stupid or wrong in light of the final library
|
||||
// specifications. The code needs to be reviewed line-by-line to elmininate
|
||||
// such problems.
|
||||
|
||||
//****************************************************************************//
|
||||
|
||||
// BOOST_POSIX or BOOST_WINDOWS specify which API to use, not the current
|
||||
// operating system. GCC defaults to BOOST_POSIX; it doesn't predefine _WIN32.
|
||||
|
||||
# if !defined( BOOST_WINDOWS ) && !defined( BOOST_POSIX )
|
||||
# if defined(_WIN32)
|
||||
# define BOOST_WINDOWS
|
||||
# else
|
||||
# define BOOST_POSIX
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/exception.hpp>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_NO_STDC_NAMESPACE
|
||||
namespace std { using ::strlen; }
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
|
||||
// helpers -----------------------------------------------------------------//
|
||||
|
||||
namespace
|
||||
{
|
||||
// POSIX & Windows cases: "", "/", "/foo", "foo", "foo/bar"
|
||||
// Windows only cases: "c:", "c:/", "c:foo", "c:/foo",
|
||||
// "prn:", "//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;
|
||||
|
||||
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 );
|
||||
# endif
|
||||
|
||||
return ( pos == std::string::npos // path itself must be a leaf (or empty)
|
||||
# ifdef BOOST_WINDOWS
|
||||
|| (pos == 1 && str[0] == '/') // or share
|
||||
# endif
|
||||
) ? 0 // so leaf is entire string
|
||||
: pos + 1; // or starts after delimiter
|
||||
}
|
||||
|
||||
void first_name( const std::string & src, std::string & target )
|
||||
{
|
||||
target = ""; // VC++ 6.0 doesn't have string::clear()
|
||||
std::string::const_iterator itr( src.begin() );
|
||||
|
||||
# ifdef BOOST_WINDOWS
|
||||
// deal with //share
|
||||
if ( src.size() >= 2 && src[0] == '/' && src[1] == '/' )
|
||||
{ target = "//"; itr += 2; }
|
||||
# endif
|
||||
|
||||
while ( itr != src.end()
|
||||
# ifdef BOOST_WINDOWS
|
||||
&& *itr != ':'
|
||||
# endif
|
||||
&& *itr != '/' ) { target += *itr++; }
|
||||
|
||||
if ( itr == src.end() ) return;
|
||||
|
||||
# ifdef BOOST_WINDOWS
|
||||
if ( *itr == ':' )
|
||||
{
|
||||
target += *itr++;
|
||||
if ( itr == src.end() ) return;
|
||||
if ( *itr == '/' ) { target += *itr++; }
|
||||
return;
|
||||
}
|
||||
# endif
|
||||
|
||||
// *itr is '/'
|
||||
if ( itr == src.begin() ) { target += '/'; }
|
||||
return;
|
||||
}
|
||||
|
||||
const char invalid_chars[] =
|
||||
"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"
|
||||
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"
|
||||
"<>:\"/\\|*?";
|
||||
// note that the terminating '\0' is part of the string - thus the size below
|
||||
// is sizeof(invalid_chars) rather than sizeof(invalid_chars)-1. I
|
||||
const std::string invalid_generic( invalid_chars, sizeof(invalid_chars) );
|
||||
|
||||
const std::string valid_posix(
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-" );
|
||||
|
||||
const std::string valid_boost_file(
|
||||
"abcdefghijklmnopqrstuvwxyz0123456789._-" );
|
||||
const std::string valid_boost_directory(
|
||||
"abcdefghijklmnopqrstuvwxyz0123456789_-" );
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace filesystem
|
||||
{
|
||||
|
||||
// error checking functions --------------------------------------------//
|
||||
|
||||
|
||||
bool generic_name( const std::string & name )
|
||||
{
|
||||
return name.size() != 0
|
||||
&& name.find_first_of( invalid_generic ) == std::string::npos
|
||||
&& name != "."
|
||||
&& name != ".."
|
||||
&& *name.begin() != ' '
|
||||
&& *(name.end()-1) != ' ';
|
||||
}
|
||||
|
||||
bool posix_name( const std::string & name )
|
||||
{
|
||||
return name.find_first_not_of( valid_posix ) == std::string::npos
|
||||
&& name != ".";
|
||||
}
|
||||
|
||||
const path & check_posix_leaf( const path & ph )
|
||||
{
|
||||
if ( !posix_name( ph.leaf() ) )
|
||||
throw filesystem_error( "invalid posix name: \""
|
||||
+ ph.leaf() + "\"" );
|
||||
return ph;
|
||||
}
|
||||
|
||||
bool boost_file_name( const std::string & name )
|
||||
{
|
||||
return name.size() <= 31
|
||||
&& name.find_first_not_of( valid_boost_file ) == std::string::npos
|
||||
&& name != ".";
|
||||
}
|
||||
|
||||
bool boost_directory_name( const std::string & name )
|
||||
{
|
||||
return name.size() <= 31
|
||||
&& name.find_first_not_of( valid_boost_directory ) == std::string::npos;
|
||||
}
|
||||
|
||||
// path implementation -------------------------------------------------//
|
||||
|
||||
path::path( const std::string & src )
|
||||
{
|
||||
m_path_append( src );
|
||||
}
|
||||
|
||||
path::path( const char * src )
|
||||
{
|
||||
m_path_append( src );
|
||||
}
|
||||
|
||||
path::path( const std::string & src, path_format )
|
||||
{
|
||||
m_path_append( src, platform );
|
||||
}
|
||||
|
||||
path::path( const char * src, path_format )
|
||||
{
|
||||
m_path_append( src, platform );
|
||||
}
|
||||
|
||||
path & path::operator <<=( const path & rhs )
|
||||
{
|
||||
m_path_append( rhs.m_path, nocheck );
|
||||
return *this;
|
||||
}
|
||||
|
||||
void path::m_path_append( const std::string & src, source_context context )
|
||||
{
|
||||
// convert backslash to forward slash if context is "platform"
|
||||
// check names if context is "generic"
|
||||
// allow system-specific-root if context is not "generic"
|
||||
|
||||
assert( src.size() == std::strlen( src.c_str() ) ); // no embedded 0
|
||||
|
||||
if ( src.size() == 0 ) return;
|
||||
|
||||
std::string::const_iterator itr( src.begin() );
|
||||
|
||||
// system-specific-root like drive: or first slash of //share
|
||||
if ( context != generic )
|
||||
{
|
||||
if ( *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;
|
||||
}
|
||||
|
||||
// relative-path ::= element { "/" element }
|
||||
while ( itr != src.end() )
|
||||
{
|
||||
// append '/' if needed
|
||||
if ( !is_null() // append '/'
|
||||
&& *(m_path.end()-1) != ':' && *(m_path.end()-1) != '/' )
|
||||
m_path += '/';
|
||||
|
||||
if ( *itr == '.'&& (itr+1) != src.end() && *(itr+1) == '.' ) // ".."
|
||||
{
|
||||
if ( m_path.size() >= 2 // there is a named parent directory present
|
||||
&& *(m_path.end()-1) == '/'
|
||||
# ifdef BOOST_WINDOWS
|
||||
&& *(m_path.end()-2) != ':'
|
||||
# endif
|
||||
&& *(m_path.end()-2) != '.' )
|
||||
{
|
||||
// reference to parent so erase child
|
||||
std::string::iterator child( m_path.end()-2 );
|
||||
|
||||
while ( child != m_path.begin() && *child != '/'
|
||||
# ifdef BOOST_WINDOWS
|
||||
&& *child != ':'
|
||||
# endif
|
||||
) --child;
|
||||
|
||||
// only erase '/' if it is a separator rather than part of the root
|
||||
if ( (*child == '/'
|
||||
&& (child == m_path.begin()
|
||||
# ifdef BOOST_WINDOWS
|
||||
|| *(child-1) == ':'))
|
||||
|| *child == ':'
|
||||
# else
|
||||
))
|
||||
# endif
|
||||
) ++child;
|
||||
|
||||
m_path.erase( child, m_path.end() );
|
||||
}
|
||||
else { m_path += ".."; }
|
||||
++itr;
|
||||
++itr;
|
||||
} // ".."
|
||||
else // name
|
||||
{
|
||||
std::string name;
|
||||
do
|
||||
{ name += *itr; }
|
||||
while ( ++itr != src.end() && *itr != '/'
|
||||
# ifdef BOOST_WINDOWS
|
||||
&& (*itr != '\\' || context != platform)
|
||||
# endif
|
||||
);
|
||||
|
||||
if ( context == generic && !generic_name( name ) )
|
||||
{
|
||||
throw filesystem_error( "invalid path name: \""
|
||||
+ src + "\"" );
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
} // while more elements
|
||||
}
|
||||
|
||||
const path::iterator path::begin() const
|
||||
{
|
||||
iterator itr;
|
||||
itr.base().path_ptr = this;
|
||||
first_name( m_path, itr.base().name );
|
||||
itr.base().pos = 0;
|
||||
return itr;
|
||||
}
|
||||
|
||||
void path::m_replace_leaf( const char * new_leaf )
|
||||
{
|
||||
m_path.erase( leaf_pos( m_path, m_path.size() ) );
|
||||
m_path += new_leaf;
|
||||
}
|
||||
|
||||
const std::string path::leaf() const
|
||||
{
|
||||
return m_path.substr( leaf_pos( m_path, m_path.size() ) );
|
||||
}
|
||||
|
||||
const path path::branch() const
|
||||
{
|
||||
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 );
|
||||
}
|
||||
|
||||
//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:"
|
||||
//}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
void path_itr_imp::operator++()
|
||||
{
|
||||
assert( pos < path_ptr->m_path.size() ); // detect increment past end
|
||||
pos += name.size();
|
||||
if ( pos == path_ptr->m_path.size() )
|
||||
{
|
||||
name = ""; // not strictly required, but might aid debugging
|
||||
return;
|
||||
}
|
||||
if ( path_ptr->m_path[pos] == '/' ) ++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 );
|
||||
}
|
||||
|
||||
void path_itr_imp::operator--()
|
||||
{
|
||||
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;
|
||||
pos = leaf_pos( path_ptr->m_path, end_pos );
|
||||
name = path_ptr->m_path.substr( pos, end_pos - pos );
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace filesystem
|
||||
} // namespace boost
|
34
test/Jamfile
Normal file
34
test/Jamfile
Normal file
@ -0,0 +1,34 @@
|
||||
#
|
||||
# !!!!!!!!!!!!!!!! You must set BOOST_ROOT=../../.. before running bjam test !!!!!!!!!!!!!!!!!!!!!!
|
||||
#
|
||||
|
||||
|
||||
subproject libs/filesystem/test ;
|
||||
|
||||
# bring in rules for testing
|
||||
SEARCH on testing.jam = $(BOOST_BUILD_PATH) ;
|
||||
include testing.jam ;
|
||||
|
||||
{
|
||||
# look in BOOST_ROOT for sources first, just in this Jamfile
|
||||
local SEARCH_SOURCE = $(BOOST_ROOT) $(SEARCH_SOURCE) ;
|
||||
|
||||
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
|
||||
]
|
||||
;
|
||||
}
|
134
test/fstream_test.cpp
Normal file
134
test/fstream_test.cpp
Normal file
@ -0,0 +1,134 @@
|
||||
// fstream_test.cpp --------------------------------------------------------//
|
||||
|
||||
// (C) Copyright 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 for most recent version including documentation.
|
||||
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <string>
|
||||
#include <cstdio> // for std::remove
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifdef BOOST_NO_STDC_NAMESPACE
|
||||
namespace std { using ::remove; }
|
||||
#endif
|
||||
|
||||
|
||||
#define BOOST_INCLUDE_MAIN
|
||||
#include <boost/test/test_tools.hpp>
|
||||
|
||||
int test_main( int, char*[] )
|
||||
{
|
||||
{ // basic_filebuf runtime results are ignored; as long as they don't crash
|
||||
// or throw we are satisfied
|
||||
fs::basic_filebuf<char> bfb;
|
||||
fs::filebuf cfb;
|
||||
|
||||
bfb.open( "fstream_test_bffoo", std::ios_base::in );
|
||||
cfb.open( "fstream_test_bffoo", std::ios_base::in );
|
||||
|
||||
# ifndef BOOST_NO_STD_WSTRING
|
||||
fs::wfilebuf wfb;
|
||||
wfb.open( "fstream_test_bffoo", std::ios_base::in );
|
||||
# endif
|
||||
}
|
||||
|
||||
std::remove( "fstream_test_bfoo" );
|
||||
std::remove( "fstream_test_cfoo" );
|
||||
# ifndef BOOST_NO_STD_WSTRING
|
||||
std::remove( "fstream_test_wfoo" );
|
||||
# endif
|
||||
{
|
||||
fs::basic_ofstream<char> bofs( "fstream_test_bfoo" );
|
||||
fs::ofstream cofs( "fstream_test_cfoo" );
|
||||
|
||||
BOOST_TEST( bofs.is_open() );
|
||||
BOOST_TEST( cofs.is_open() );
|
||||
|
||||
bofs << "fstream_test_bfoo";
|
||||
cofs << "fstream_test_cfoo";
|
||||
|
||||
// these will fail, but they still test the interface
|
||||
bofs.open( "fstream_test_bfoo" );
|
||||
cofs.open( "fstream_test_cfoo" );
|
||||
|
||||
# ifndef BOOST_NO_STD_WSTRING
|
||||
fs::wofstream wofs( "fstream_test_wfoo" );
|
||||
BOOST_TEST( wofs.is_open() );
|
||||
wofs << L"fstream_test_wfoo";
|
||||
wofs.open( "fstream_test_wfoo" ); // expected to fail
|
||||
# endif
|
||||
}
|
||||
|
||||
{
|
||||
fs::basic_ifstream<char> bifs( "fstream_test_bfoo" );
|
||||
fs::ifstream cifs( "fstream_test_cfoo" );
|
||||
|
||||
BOOST_TEST( bifs.is_open() );
|
||||
BOOST_TEST( cifs.is_open() );
|
||||
|
||||
std::string b;
|
||||
std::string c;
|
||||
|
||||
bifs >> b;
|
||||
cifs >> c;
|
||||
|
||||
BOOST_TEST( b == "fstream_test_bfoo" );
|
||||
BOOST_TEST( c == "fstream_test_cfoo" );
|
||||
|
||||
// these will fail, but they still test the interface
|
||||
bifs.open( "fstream_test_bfoo" );
|
||||
cifs.open( "fstream_test_cfoo" );
|
||||
|
||||
# ifndef BOOST_NO_STD_WSTRING
|
||||
fs::wifstream wifs( "fstream_test_wfoo" );
|
||||
BOOST_TEST( wifs.is_open() );
|
||||
std::wstring w;
|
||||
wifs >> w;
|
||||
BOOST_TEST( w == L"fstream_test_wfoo" );
|
||||
wifs.open( "fstream_test_wfoo" ); // expected to fail
|
||||
# endif
|
||||
}
|
||||
|
||||
{
|
||||
fs::basic_fstream<char> bfs( "fstream_test_bfoo" );
|
||||
fs::fstream cfs( "fstream_test_cfoo" );
|
||||
|
||||
BOOST_TEST( bfs.is_open() );
|
||||
BOOST_TEST( cfs.is_open() );
|
||||
|
||||
std::string b;
|
||||
std::string c;
|
||||
|
||||
bfs >> b;
|
||||
cfs >> c;
|
||||
|
||||
BOOST_TEST( b == "fstream_test_bfoo" );
|
||||
BOOST_TEST( c == "fstream_test_cfoo" );
|
||||
|
||||
// these will fail, but they still test the interface
|
||||
bfs.open( "fstream_test_bfoo" );
|
||||
cfs.open( "fstream_test_cfoo" );
|
||||
|
||||
# ifndef BOOST_NO_STD_WSTRING
|
||||
fs::wfstream wfs( "fstream_test_wfoo" );
|
||||
BOOST_TEST( wfs.is_open() );
|
||||
std::wstring w;
|
||||
wfs >> w;
|
||||
BOOST_TEST( w == L"fstream_test_wfoo" );
|
||||
wfs.open( "fstream_test_wfoo" ); // expected to fail
|
||||
# endif
|
||||
}
|
||||
|
||||
// std::remove( "fstream_test_bfoo" );
|
||||
// std::remove( "fstream_test_cfoo" );
|
||||
// # ifndef BOOST_NO_STD_WSTRING
|
||||
// std::remove( "fstream_test_wfoo" );
|
||||
// # endif
|
||||
return 0;
|
||||
}
|
220
test/operations_test.cpp
Normal file
220
test/operations_test.cpp
Normal file
@ -0,0 +1,220 @@
|
||||
// Boost operations_test.cpp -----------------------------------------------//
|
||||
|
||||
// (C) Copyright 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 for most recent version including documentation.
|
||||
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/filesystem/exception.hpp>
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
//#include <boost/test/test_tools.hpp>
|
||||
#include <boost/test/minimal.hpp>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
using boost::bind;
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
namespace
|
||||
{
|
||||
fs::directory_iterator end_itr;
|
||||
|
||||
void create_file( const fs::path & ph, const std::string & contents )
|
||||
{
|
||||
std::ofstream f( ph.file_path().c_str() );
|
||||
if ( !f )
|
||||
throw fs::filesystem_error( "ofstream(): " + ph.generic_path() );
|
||||
if ( !contents.empty() ) f << contents;
|
||||
}
|
||||
|
||||
void verify_file( const fs::path & ph, const std::string & expected )
|
||||
{
|
||||
std::ifstream f( ph.file_path().c_str() );
|
||||
if ( !f )
|
||||
throw fs::filesystem_error( "ifstream(): " + ph.generic_path() );
|
||||
std::string contents;
|
||||
f >> contents;
|
||||
if ( contents != expected )
|
||||
throw fs::filesystem_error("verify_file(): " + ph.generic_path()
|
||||
+ " contents \"" + contents
|
||||
+ "\" != \"" + expected + "\"" );
|
||||
}
|
||||
|
||||
template< typename F >
|
||||
bool throws_fs_error( F func )
|
||||
{
|
||||
try { func(); }
|
||||
|
||||
catch ( const fs::filesystem_error & /*ex*/ )
|
||||
{
|
||||
// std::cout << ex.what() << "\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
// test_main ---------------------------------------------------------------//
|
||||
|
||||
int test_main( int, char * [] )
|
||||
{
|
||||
std::cout << "implemenation name: "
|
||||
<< fs::detail::implementation_name() << "\n";
|
||||
std::cout << "initial_directory() is \""
|
||||
<< fs::initial_directory().generic_path()
|
||||
<< "\"\n";
|
||||
|
||||
fs::path dir( fs::initial_directory() << "temp_fs_test_directory" );
|
||||
|
||||
if ( std::strcmp( fs::detail::implementation_name(), "Windows" ) == 0 )
|
||||
{
|
||||
BOOST_TEST( dir.generic_path().size() > 1
|
||||
&& dir.generic_path()[1] == ':' ); // verify path includes drive
|
||||
}
|
||||
|
||||
fs::path ng( " no-way, Jose ", fs::system_specific );
|
||||
|
||||
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, dir ) ) );
|
||||
BOOST_TEST( throws_fs_error( bind( fs::_is_empty, dir ) ) );
|
||||
|
||||
fs::create_directory( dir );
|
||||
|
||||
BOOST_TEST( fs::exists( dir ) );
|
||||
BOOST_TEST( fs::_is_empty( dir ) );
|
||||
|
||||
BOOST_TEST( fs::is_directory( dir ) );
|
||||
|
||||
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 ) );
|
||||
|
||||
{
|
||||
fs::directory_iterator dir_itr( dir );
|
||||
BOOST_TEST( dir_itr->leaf() == "d1" );
|
||||
}
|
||||
|
||||
// create a second directory named d2
|
||||
fs::path d2( dir << "d2" );
|
||||
fs::create_directory(d2 );
|
||||
BOOST_TEST( fs::exists( d2 ) );
|
||||
BOOST_TEST( fs::is_directory( d2 ) );
|
||||
|
||||
{
|
||||
fs::directory_iterator dir_itr( dir );
|
||||
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( (++fs::directory_iterator(dir))->leaf() == "d1" );
|
||||
}
|
||||
}
|
||||
|
||||
// create an empty file named "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";
|
||||
create_file( file_ph, "foobar1" );
|
||||
BOOST_TEST( fs::exists( file_ph ) );
|
||||
BOOST_TEST( !fs::is_directory( file_ph ) );
|
||||
verify_file( file_ph, "foobar1" );
|
||||
|
||||
// there was an inital bug in directory_iterator that caused premature
|
||||
// close of an OS handle. This block will detect regression.
|
||||
{
|
||||
fs::directory_iterator di;
|
||||
{ di = fs::directory_iterator( dir ); }
|
||||
BOOST_TEST( ++di != fs::directory_iterator() );
|
||||
}
|
||||
|
||||
// copy_file() tests
|
||||
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" );
|
||||
|
||||
// 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" );
|
||||
|
||||
// make sure can't rename() a non-existent file
|
||||
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" ) ) );
|
||||
|
||||
// make sure can't rename() to a nonexistent parent directory
|
||||
BOOST_TEST( throws_fs_error( bind( fs::rename, dir << "f1", dir << "d3/f3" ) ) );
|
||||
|
||||
// rename() on directory
|
||||
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" ) );
|
||||
|
||||
// remove() tests on file
|
||||
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::exists( file_ph ) );
|
||||
fs::remove( "no-such-file" ); // should be harmless
|
||||
fs::remove( "no-such-directory/no-such-file" ); // ditto
|
||||
|
||||
// remove test on directory
|
||||
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( !fs::exists( d1 ) );
|
||||
|
||||
// post-test cleanup
|
||||
BOOST_TEST( fs::remove_all( dir ) != 0 );
|
||||
// above was added just to simplify testing, but it ended up detecting
|
||||
// a bug (failure to close an internal search handle).
|
||||
BOOST_TEST( !fs::exists( dir ) );
|
||||
BOOST_TEST( fs::remove_all( dir ) == 0 );
|
||||
|
||||
return 0;
|
||||
} // main
|
||||
|
315
test/path_test.cpp
Normal file
315
test/path_test.cpp
Normal file
@ -0,0 +1,315 @@
|
||||
// path_test program -------------------------------------------------------//
|
||||
|
||||
// (C) Copyright 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 for most recent version including documentation.
|
||||
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/filesystem/exception.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
using boost::filesystem::path;
|
||||
using boost::next;
|
||||
using boost::prior;
|
||||
|
||||
#define BOOST_INCLUDE_MAIN
|
||||
#include <boost/test/test_tools.hpp>
|
||||
|
||||
namespace {
|
||||
int errors;
|
||||
|
||||
void check( const fs::path & source,
|
||||
const std::string & expected )
|
||||
{
|
||||
if ( source.generic_path()== expected ) return;
|
||||
|
||||
++errors;
|
||||
|
||||
std::cout << "source.generic_path(): \"" << source.generic_path()
|
||||
<< "\" != expected: \"" << expected
|
||||
<< "\"" << std::endl;
|
||||
}
|
||||
|
||||
void check_throw( const std::string & arg )
|
||||
{
|
||||
try
|
||||
{
|
||||
fs::path arg_path( arg );
|
||||
++errors;
|
||||
std::cout << "failed to throw with argument \"" << arg
|
||||
<< "\"" << std::endl;
|
||||
}
|
||||
catch ( const fs::filesystem_error & /*ex*/ )
|
||||
{
|
||||
// std::cout << ex.what() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
int test_main( int, char*[] )
|
||||
{
|
||||
|
||||
path p1( "fe/fi/fo/fum" );
|
||||
path p2( p1 );
|
||||
path p3;
|
||||
p3 = p2;
|
||||
|
||||
// p1.branch() = 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( fs::check_posix_leaf( "foo" ) );
|
||||
|
||||
BOOST_TEST( p1.generic_path() == p2.generic_path() );
|
||||
BOOST_TEST( p1.generic_path() == p3.generic_path() );
|
||||
BOOST_TEST( path( "foo" ).leaf() == "foo" );
|
||||
BOOST_TEST( path( "foo" ).branch().generic_path() == "" );
|
||||
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 );
|
||||
|
||||
check( "", "" );
|
||||
|
||||
check( "foo", "foo" );
|
||||
check( path("") << "foo", "foo" );
|
||||
check( path("foo") << "", "foo" );
|
||||
|
||||
check( "foo/bar", "foo/bar" );
|
||||
check( path("foo") << "bar", "foo/bar" );
|
||||
check( path("foo") << path("bar"), "foo/bar" );
|
||||
check( "foo" << path("bar"), "foo/bar" );
|
||||
|
||||
check( "a/b", "a/b" ); // probe for length effects
|
||||
check( path("a") << "b", "a/b" );
|
||||
|
||||
check( "..", ".." );
|
||||
check( path("..") << "", ".." );
|
||||
check( path("") << "..", ".." );
|
||||
|
||||
check( "../..", "../.." );
|
||||
check( path("..") << ".." , "../.." );
|
||||
|
||||
check( "../foo", "../foo" );
|
||||
check( path("..") << "foo" , "../foo" );
|
||||
|
||||
check( "foo/..", "" );
|
||||
check( path("foo") << ".." , "" );
|
||||
|
||||
check( "../f", "../f" );
|
||||
check( path("..") << "f" , "../f" );
|
||||
|
||||
check( "f/..", "" );
|
||||
check( path("f") << ".." , "" );
|
||||
|
||||
check( "foo/../..", ".." );
|
||||
check( path("foo") << ".." << ".." , ".." );
|
||||
|
||||
check( "foo/../../..", "../.." );
|
||||
check( path("foo") << ".." << ".." << ".." , "../.." );
|
||||
|
||||
check( "foo/../bar", "bar" );
|
||||
check( path("foo") << ".." << "bar" , "bar" );
|
||||
|
||||
check( "foo/bar/..", "foo" );
|
||||
check( path("foo") << "bar" << ".." , "foo" );
|
||||
|
||||
check( "foo/bar/../..", "" );
|
||||
check( path("foo") << "bar" << ".." << "..", "" );
|
||||
|
||||
check( "foo/bar/../blah", "foo/blah" );
|
||||
check( path("foo") << "bar" << ".." << "blah", "foo/blah" );
|
||||
|
||||
check( "f/../b", "b" );
|
||||
check( path("f") << ".." << "b" , "b" );
|
||||
|
||||
check( "f/b/..", "f" );
|
||||
check( path("f") << "b" << ".." , "f" );
|
||||
|
||||
check( "f/b/../a", "f/a" );
|
||||
check( path("f") << "b" << ".." << "a", "f/a" );
|
||||
|
||||
check( "foo/bar/blah/../..", "foo" );
|
||||
check( path("foo") << "bar" << "blah" << ".." << "..", "foo" );
|
||||
|
||||
check( "foo/bar/blah/../../bletch", "foo/bletch" );
|
||||
check( path("foo") << "bar" << "blah" << ".." << ".." << "bletch", "foo/bletch" );
|
||||
|
||||
BOOST_TEST( fs::posix_name("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.-_") );
|
||||
BOOST_TEST( !fs::posix_name("F$O") );
|
||||
BOOST_TEST( !fs::posix_name(".") );
|
||||
BOOST_TEST( !fs::boost_file_name("ABCDEFGHIJKLMNOPQRSTUVWXYZ") );
|
||||
BOOST_TEST( fs::boost_file_name("abcdefghijklmnopqrstuvwxyz") );
|
||||
BOOST_TEST( fs::boost_file_name("0123456789.-_") );
|
||||
BOOST_TEST( fs::boost_file_name("1234567890123456789012345678901") );
|
||||
BOOST_TEST( !fs::boost_file_name("12345678901234567890123456789012") );
|
||||
BOOST_TEST( !fs::boost_file_name("F$O") );
|
||||
BOOST_TEST( !fs::boost_file_name(".") );
|
||||
BOOST_TEST( !fs::boost_directory_name("ABCDEFGHIJKLMNOPQRSTUVWXYZ") );
|
||||
BOOST_TEST( fs::boost_directory_name("abcdefghijklmnopqrstuvwxyz") );
|
||||
BOOST_TEST( fs::boost_directory_name("0123456789-_") );
|
||||
BOOST_TEST( fs::boost_directory_name("1234567890123456789012345678901") );
|
||||
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" );
|
||||
check_throw( " " );
|
||||
check_throw( " foo" );
|
||||
check_throw( "foo " );
|
||||
check_throw( ">" );
|
||||
check_throw( "<" );
|
||||
check_throw( ":" );
|
||||
check_throw( "." );
|
||||
check_throw( "\"" );
|
||||
check_throw( "|" );
|
||||
|
||||
check_throw( "c:" );
|
||||
check_throw( "c:/" );
|
||||
check_throw( "//share" );
|
||||
check_throw( "prn:" );
|
||||
|
||||
path itr_ck( "/foo/bar", fs::system_specific );
|
||||
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" ) );
|
||||
BOOST_TEST( ++itr == itr_ck.end() );
|
||||
BOOST_TEST( *--itr == std::string( "bar" ) );
|
||||
BOOST_TEST( *--itr == std::string( "foo" ) );
|
||||
BOOST_TEST( *--itr == std::string( "/" ) );
|
||||
|
||||
itr_ck = "";
|
||||
BOOST_TEST( itr_ck.begin() == itr_ck.end() );
|
||||
|
||||
itr_ck = path( "/", fs::system_specific );
|
||||
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 );
|
||||
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() );
|
||||
BOOST_TEST( next( itr_ck.begin() ) == prior( itr_ck.end() ) );
|
||||
BOOST_TEST( *prior( itr_ck.end() ) == std::string( "foo" ) );
|
||||
BOOST_TEST( *prior(prior( itr_ck.end() )) == std::string( "/" ) );
|
||||
BOOST_TEST( prior(prior( itr_ck.end() )) == itr_ck.begin() );
|
||||
|
||||
itr_ck = "foo";
|
||||
BOOST_TEST( *itr_ck.begin() == std::string( "foo" ) );
|
||||
BOOST_TEST( next( itr_ck.begin() ) == itr_ck.end() );
|
||||
BOOST_TEST( *prior( itr_ck.end() ) == std::string( "foo" ) );
|
||||
BOOST_TEST( prior( itr_ck.end() ) == itr_ck.begin() );
|
||||
|
||||
if ( std::strcmp( fs::detail::implementation_name(), "Windows" ) == 0 )
|
||||
{
|
||||
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::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: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() );
|
||||
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() );
|
||||
BOOST_TEST( *prior( itr_ck.end() ) == std::string( "foo" ) );
|
||||
BOOST_TEST( *prior(prior( itr_ck.end() )) == std::string( "c:/" ) );
|
||||
|
||||
itr_ck = path( "//share", fs::system_specific );
|
||||
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 );
|
||||
BOOST_TEST( *itr_ck.begin() == std::string( "//share" ) );
|
||||
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() );
|
||||
BOOST_TEST( *prior( itr_ck.end() ) == std::string( "foo" ) );
|
||||
BOOST_TEST( *prior(prior( itr_ck.end() )) == std::string( "//share" ) );
|
||||
|
||||
itr_ck = path( "prn:", fs::system_specific );
|
||||
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";
|
||||
|
||||
return errors;
|
||||
}
|
49
test/recursive_dir_itr_test.cpp
Normal file
49
test/recursive_dir_itr_test.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
// recursive_dir_itr_test program ------------------------------------------//
|
||||
|
||||
// (C) Copyright 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 for most recent version including documentation.
|
||||
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/filesystem/recursive_directory_iterator.hpp>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bool dummy( const fs::path & /*pth*/ )
|
||||
{
|
||||
// std::cout << "predicate called with " << pth.generic_path() << '\n';
|
||||
return true;
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
int main( int argc, char * argv[] )
|
||||
{
|
||||
fs::path dir( argc > 1
|
||||
? fs::path( argv[1], fs::system_specific )
|
||||
: fs::initial_directory() );
|
||||
|
||||
std::cout << "Directory being inspected: " << dir.generic_path() << std::endl;
|
||||
|
||||
typedef bool(*pred_type)(const fs::path&);
|
||||
|
||||
fs::recursive_directory_iterator<pred_type> rdi( dir , dummy );
|
||||
fs::recursive_directory_iterator<pred_type> rdi_end;
|
||||
|
||||
for ( ; rdi != rdi_end; ++rdi )
|
||||
{
|
||||
std::cout << (*rdi).generic_path() << std::endl;
|
||||
std::cout << rdi->generic_path() << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user