initial commit - review comments not yet applied

[SVN r15831]
This commit is contained in:
Beman Dawes 2002-10-09 19:49:35 +00:00
commit 543669496a
25 changed files with 4158 additions and 0 deletions

96
.gitattributes vendored Normal file
View 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
View 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
View 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.&nbsp; Scripts were written in
Python, Perl, Bash, and Windows command languages.&nbsp; 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.&nbsp; The need is particularly acute
when C++ is the only toolset allowed in the tool chain.&nbsp; File system
operations are provided by many languages&nbsp;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>
&nbsp;</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>
&nbsp;</li>
<li>Avoid dangerous programming practices. Particularly, all-too-easy-to-ignore error notifications
and use of global variables.&nbsp;If a dangerous feature is provided, identify it as such.<br>
<br>
Rationale: Normally this would be covered by &quot;the usual Boost requirements...&quot;,
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 &quot;current
working directory&quot;.<br>
&nbsp;</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.&nbsp; 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.&nbsp; 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.&nbsp;
Thus the need to interface smoothly with standard library I/O.<br>
&nbsp;</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>
&nbsp;</li>
<li>The usual Boost <a href="../../../more/lib_guide.htm">requirements and
guidelines</a> apply.<br>
&nbsp;</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>
&nbsp;</li>
<li>Avoid giving the illusion of portability where portability in fact does not
exist.<br>
<br>
Rationale: Defining important behavior unspecified or &quot;implementation defined&quot; 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>
&nbsp;</li>
<li>Some file systems provide both a long and short form of filenames.<br>
&nbsp;</li>
<li>Some file systems have different syntax for file paths and directory
paths.<br>
&nbsp;</li>
<li>Some file systems have different rules for valid file names and valid
directory names.<br>
&nbsp;</li>
<li>Some file systems (ISO-9660, level 1, for example) use very restricted
(so-called 8.3) file names.<br>
&nbsp;</li>
<li>Some file systems allow other file systems with different
characteristics to be &quot;mounted&quot; within a directory tree.&nbsp; Thus a
ISO-9660 or Windows
file system may end up as a sub-tree of a POSIX directory tree.<br>
&nbsp;</li>
<li>Wide-character versions of directory and file operations are available on some operating
systems, and not available on others.<br>
&nbsp;</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>
&nbsp;</li>
<li>Some file systems have a concept of file &quot;version number&quot; or &quot;generation
number&quot;.&nbsp; Some don't.<br>
&nbsp;</li>
<li>Not all file systems use single character separators in path names.&nbsp; Some use
paired notations. A typical fully-specified OpenVMS filename
might look something like this:<br>
<br>
<code>&nbsp;&nbsp; DISK$SCRATCH:[GEORGE.PROJECT1.DAT]BIG_DATA_FILE.NTP;5<br>
</code><br>
The general OpenVMS format is:<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;
<i>Device:[directories.dot.separated]filename.extension;version_number</i><br>
&nbsp;</li>
<li>For common file systems, determining if two descriptors are for same
entity is extremely difficult or impossible.&nbsp; 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>
&nbsp;</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.&nbsp; 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.&nbsp;For example:<br>
<br>
<code>&nbsp;&nbsp;&nbsp;&nbsp; assert( exists(&quot;foo&quot;) == exists(&quot;foo&quot;) );
// may fail!<br>
&nbsp;&nbsp;&nbsp;&nbsp; assert( is_directory(&quot;foo&quot;) == is_directory(&quot;foo&quot;);
// may fail!<br>
</code><br>
In the first example, the file may have been deleted between calls to
exists().&nbsp; 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>
&nbsp;</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.&nbsp; 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( &quot;foo&quot;
)</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&lt;string&gt;</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.&nbsp;
Rather, the programmer must think out the question &quot;What operating systems do I
want this path to be portable to?&quot;&nbsp; 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.&nbsp; Some with
operations functions.&nbsp; 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,&nbsp; is much simpler and straightforward, although it does depend to
some extent on programmer discipline.&nbsp; 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&nbsp;Std&nbsp;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
View 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>
&nbsp;</li>
<li>Finish portability guide and checking functions. Get opinions on default, Boost, and other error checks.&nbsp; POSIX?&nbsp;
Windows? Mac?&nbsp; ISO 6990?<br>
&nbsp;</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?&nbsp;
I doubt it.&nbsp; Maybe there should be a checking function that verifies that
generic_path() contains no <code>&quot;..&quot;</code>.<br>
&nbsp;</li>
<li>Once the review is complete, ask for help porting to the Mac, etc.<br>
&nbsp;</li>
<li>From John Maddock:</li>
</ul>
<blockquote>
<pre>&gt;All the functions generic_path, file_path, directory_path, leaf, and
&gt;branch,
&gt;are under-documented IMO. I had to read the specs quite closely before I
&gt;could figure out which did what. Adding examples to each would probably be
&gt;a help, or maybe a &quot;description&quot; section that provides a less terse
&gt;description than the standardese.</pre>
</blockquote>
<ul>
<li>Change remove() to return a bool, now that the file doesn't have to
exist..&nbsp; (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
View 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.&nbsp; 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
View 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.&nbsp; Thus for the primary &quot;portable script-style file system
operations&quot; 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.&nbsp; 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?&nbsp; 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.&nbsp; Gaining some advantage by using features specific to particular
operating systems is not a requirement.</p>
<p>Furthermore, concepts like &quot;posix_file_system&quot;
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 &quot;portable script-style
file system operations&quot; 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.&nbsp;&nbsp;&nbsp; </p>
<p>The case for the &quot;handle&quot; (opaque data type to identify a file)
style may be strongest for directory iterator value type.&nbsp; (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 &quot;non-directory
path&quot; 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 &quot;directories aren't files&quot; 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.&nbsp;
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.&nbsp; OTOH, the specific functionality needed for several trial
applications was very easy for the user to construct from the lower-level
toolkit functions.&nbsp; 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.&nbsp;Return codes or error notification variables are often ignored
by programmers.&nbsp; 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 &quot;read-only&quot; turned out to be so
system depend as to be disqualified as a &quot;guaranteed presence&quot; 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">&nbsp;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.&nbsp; 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.&nbsp;
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 &quot;root directory&quot; appears to be inherently non-portable.&nbsp;
For example, &quot;/&quot;&nbsp; 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).&nbsp; 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>&quot;/foo&quot; 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>&quot;c:foo&quot; is relative to the current working directory on drive &quot;c:&quot;,
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
View 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>&lt;fstream&gt;</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&nbsp; <i>
const char*</i> arguments have been replaced by <i>const path&amp;</i> arguments.</p>
<p>The Filesystem Library's <i>fstream.hpp</i> header simply uses the <i>&lt;fstream&gt;</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 &lt; class charT, class traits = std::char_traits&lt;charT&gt; &gt;
class basic_filebuf : public std::basic_filebuf&lt;charT,traits&gt;
{
public:
virtual ~basic_filebuf() {}
std::basic_filebuf&lt;charT,traits&gt; * open( const path &amp; file_ph,
std::ios_base::openmode mode );
};
typedef basic_filebuf&lt;char&gt; filebuf;
typedef basic_filebuf&lt;wchar_t&gt; wfilebuf;
template &lt; class charT, class traits = std::char_traits&lt;charT&gt; &gt;
class basic_ifstream : public std::basic_ifstream&lt;charT,traits&gt;
{
public:
basic_ifstream() {}
explicit basic_ifstream( const path &amp; file_ph,
std::ios_base::openmode mode = std::ios_base::in );
virtual ~basic_ifstream() {}
void open( const path &amp; file_ph,
std::ios_base::openmode mode = std::ios_base::in );
};
typedef basic_ifstream&lt;char&gt; ifstream;
typedef basic_ifstream&lt;wchar_t&gt; wifstream;
template &lt; class charT, class traits = std::char_traits&lt;charT&gt; &gt;
class basic_ofstream : public std::basic_ofstream&lt;charT,traits&gt;
{
public:
basic_ofstream() {}
explicit basic_ofstream( const path &amp; file_ph,
std::ios_base::openmode mode = std::ios_base::out );
virtual ~basic_ofstream() {}
void open( const path &amp; file_ph,
std::ios_base::openmode mode = std::ios_base::out );
};
typedef basic_ofstream&lt;char&gt; ofstream;
typedef basic_ofstream&lt;wchar_t&gt; wofstream;
template &lt; class charT, class traits = std::char_traits&lt;charT&gt; &gt;
class basic_fstream : public std::basic_fstream&lt;charT,traits&gt;
{
public:
basic_fstream() {}
explicit basic_fstream( const path &amp; file_ph,
std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out );
virtual ~basic_fstream() {}
void open( const path &amp; file_ph,
std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out );
};
typedef basic_fstream&lt;char&gt; fstream;
typedef basic_fstream&lt;wchar_t&gt; 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
View 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>
&nbsp;&nbsp;&nbsp; <a href="#Introduction">Introduction</a><br>
&nbsp;&nbsp;&nbsp; <a href="#tutorial">Two-minute tutorial</a><br>
&nbsp;&nbsp;&nbsp; <a href="#Examples">Examples</a><br>
&nbsp;&nbsp;&nbsp;
<a href="#Definitions">Definitions</a><br>
&nbsp;&nbsp;&nbsp;
<a href="#Requirements">Requirements</a><br>
&nbsp;&nbsp;&nbsp; <a href="#Race-condition">Race-condition danger</a><br>
&nbsp;&nbsp;&nbsp; <a href="#Acknowledgements">Acknowledgements</a></td>
<td width="50%"><font size="4">Other Documents</font><br>
&nbsp;&nbsp;&nbsp; <a href="design.htm">Library Design</a><br>
&nbsp;&nbsp;&nbsp; <a href="faq.htm">FAQ</a><br>
&nbsp;&nbsp;&nbsp; <a href="portability_guide.htm">Portability Guide</a><br>
&nbsp;&nbsp;&nbsp; <a href="path.htm"><b><i>path.hpp</i></b> documentation</a><br>
&nbsp;&nbsp;&nbsp; <a href="operations.htm"><b><i>operations.hpp</i></b> documentation</a><br>
&nbsp;&nbsp;&nbsp; <a href="fstream.htm"><b><i>fstream.hpp</i></b> documentation</a><br>
&nbsp;&nbsp;&nbsp; <a href="exception.htm"><b><i>exception.hpp</i></b> documentation</a><br>
&nbsp;&nbsp;&nbsp; <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&nbsp; 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>
&nbsp;</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>
&nbsp;</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>
&nbsp;</li>
<li>Header <i>exception.hpp</i> provides class <i>filesystem_error</i>. See
<a href="exception.htm">exception.hpp documentation</a>.<br>
&nbsp;</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 &quot;boost/filesystem/operations.hpp&quot; // includes boost/filesystem/path.hpp
#include &quot;boost/filesystem/fstream.hpp&quot; // ditto
#include &lt;iostream&gt; // 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( &quot;some_dir/file.txt&quot; );</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>&quot;some_dir:file.txt&quot;</code>, <code>&quot;[some_dir]file.txt&quot;</code>,
<code>&quot;some_dir/file.txt&quot;</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&amp;</i>, so that even though the Filesystem Library functions in
the following code snippet take <i>const path&amp;</i> arguments, the user can just
code C-style strings:</p>
<blockquote>
<pre>fs::remove_all( &quot;foobar&quot; );
fs::create_directory( &quot;foobar&quot; );
fs::ofstream file( &quot;foobar/cheeze&quot; );
file &lt;&lt; &quot;tastes good!\n&quot;;
file.close();
if ( !fs::exists( &quot;foobar/cheeze&quot; ) )
std::cout &lt;&lt; &quot;Something is rotten in foobar\n&quot;;</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&lt;&lt;</i>
appends paths:</p>
<blockquote>
<pre>fs::ifstream file1( arg_path &lt;&lt; &quot;foo/bar&quot; );
fs::ifstream file2( arg_path &lt;&lt; &quot;foo&quot; &lt;&lt; &quot;bar&quot; );</pre>
</blockquote>
<p>Note that expressions <i>arg_path &lt;&lt; &quot;foo/bar&quot;</i> and <i>arg_path &lt;&lt; &quot;foo&quot;
&lt;&lt; &quot;bar&quot;</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.&nbsp; The code
below is extracted from a real program, slightly modified for clarity:</p>
<blockquote>
<pre>bool find_file( const fs::path &amp; dir_path, // in this directory,
const std::string &amp; file_name, // search for this name,
fs::path &amp; 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-&gt;leaf() == file_name ) // see below
{
path_found = *itr;
return true;
}
}
return false;
}</pre>
</blockquote>
<p>The expression <i>itr-&gt;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&lt;std::string&gt;</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 &quot;Throws&quot; 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( &quot;foo&quot; ) == exists( &quot;foo&quot; ) );&nbsp; //
(1)<br>
<br>
remove_all( &quot;foo&quot; );<br>
assert( !exists( &quot;foo&quot; ) );&nbsp; // (2)<br>
<br>
assert( is_directory( &quot;foo&quot; ) == is_directory( &quot;foo&quot; ) ); //
(3)</code></p>
</blockquote>
<p>(1) will fail if a non-existent &quot;foo&quot; comes into existence, or an
existent &quot;foo&quot; 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 &quot;foo&quot; is created by another
thread, process, or computer.</p>
<p>(3) will fail if another thread, process, or computer removes an
existing file &quot;foo&quot; and then creates a directory named &quot;foo&quot;, 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.&nbsp; 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 &quot;illusion
of portability&quot; 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
View 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>
&nbsp;&nbsp;&nbsp; <a href="#constructors">Constructors</a><br>
&nbsp;&nbsp;&nbsp; <a href="#destructor">Destructor</a><br>
&nbsp;&nbsp;&nbsp; <a href="#other functions">Other functions</a><br>
<a href="#Non-member functions">Non-member functions</a><br>
&nbsp;&nbsp;&nbsp; <a href="#exists">exists</a><br>
&nbsp;&nbsp;&nbsp; <a href="#is_directory">is_directory</a><br>
&nbsp;&nbsp;&nbsp; <a href="#is_empty">is_empty</a><br>
&nbsp;&nbsp;&nbsp; <a href="#create_directory">create_directory</a><br>
&nbsp;&nbsp;&nbsp; <a href="#remove">remove</a><br>
&nbsp;&nbsp;&nbsp; <a href="#remove_all">remove_all</a><br>
&nbsp;&nbsp;&nbsp; <a href="#rename">rename</a><br>
&nbsp;&nbsp;&nbsp; <a href="#copy_file">copy_file</a><br>
&nbsp;&nbsp;&nbsp; <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 &amp; reference;
typedef std::input_iterator_tag iterator_category;
<a href="#constructors">directory_iterator</a>();
explicit <a href="#constructors">directory_iterator</a>( const path &amp; directory_ph );
// <a href="#other functions">other functions</a>
// ...
};
bool <a href="#exists">exists</a>( const path &amp; ph );
bool <a href="#is_directory">is_directory</a>( const path &amp; ph );
bool <a href="#is_empty">is_empty</a>( const path &amp; ph );
void <a href="#create_directory">create_directory</a>( const path &amp; directory_ph );
void <a href="#remove">remove</a>( const path &amp; ph );
unsigned long <a href="#remove_all">remove_all</a>( const path &amp; ph );
void <a href="#rename">rename</a>( const path &amp; from_path,
const path &amp; to_path );
void <a href="#copy_file">copy_file</a>( const path &amp; from_file_ph,
const path &amp; to_file_ph );
const path &amp; <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>&quot;..&quot;</code>
or <code>&quot;.&quot;</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 &amp; 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 &amp; 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 &amp; ph );</code></p>
<p><b>Returns:</b> True if the operating system reports the path represented by&nbsp;
<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.&nbsp; A compound function returning <code>
exists(ph) &amp;&amp; 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 &amp; ph );</code></p>
<p><b>Returns:</b> True if the operating system reports the path represented by&nbsp;
<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 &amp; directory_ph );</code></p>
<p><b>Postcondition:</b> <code>exists(directory_ph) &amp;&amp;
is_directory(directory_ph) &amp;&amp; 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 &amp; ph );</code></p>
<p><b>Postcondition:</b> <code>!exists( ph )</code></p>
<p><b>Throws:</b> if<code> exists(ph) &amp;&amp; is_directory(ph) &amp;&amp; !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 &amp; 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 &amp; from_ph, const path &amp; to_ph
);</code></p>
<p><b>Effects:</b> Changes the name of&nbsp; file or directory <i>from_ph</i>
to <i>to_ph</i>.</p>
<p><b>Postconditions:</b> <code>!exists(from_ph) &amp;&amp; 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 &amp; from_file_ph, const path &amp;
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 &amp; 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>&nbsp; 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
View 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.&nbsp; 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.&nbsp; 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.&nbsp; 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 { &quot;/&quot; element } </pre>
<pre>element ::= name | parent-directory </pre>
<pre>parent-directory ::= &quot;..&quot; </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.&nbsp; 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 &amp; src );
<a href="#constructors">path</a>( const char * src );
<a href="#constructors">path</a>( const std::string &amp; src, path_format );
<a href="#constructors">path</a>( const char * src, path_format );
// append operations:
path &amp; <a href="#operator-shift-equal">operator&lt;&lt;=</a>( const path &amp; rhs );
const path <a href="#operator-shift">operator&lt;&lt;</a>( const path &amp; rhs ) const;
// query functions:
bool <a href="#empty">is_null()</a> const;
const std::string &amp; <a href="#generic_path">generic_path</a>() const;
const std::string &amp; <a href="#file_path">file_path</a>() const;
const std::string &amp; <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&lt;std::string&gt; m_name; // for exposition only
};
const path <a href="#non-member operator shift">operator&lt;&lt;</a> ( const char * lhs, const path &amp; rhs );
const path <a href="#non-member operator shift">operator&lt;&lt;</a> ( const std::string &amp; lhs, const path &amp; 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&lt;&lt;,
leaf, branch</i>) is <i>const path</i> instead of <i>path</i> to disallow
expressions like <i>(p1&lt;&lt;p2) = p3</i>.&nbsp; 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&lt;std::string&gt; 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( &quot;foo/bar/data.txt&quot; );
std::cout &lt;&lt; &quot;generic_path---: &quot; &lt;&lt; my_path.generic_path() &lt;&lt; '\n'
&lt;&lt; &quot;directory_path-: &quot; &lt;&lt; my_path.directory_path() &lt;&lt; '\n'
&lt;&lt; &quot;file_path------: &quot; &lt;&lt; my_path.file_path() &lt;&lt; '\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 &amp; 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>,&nbsp; <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 &amp; 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),&nbsp; <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 &lt;&lt;=</a></h3>
<blockquote>
<pre>path &amp; operator&lt;&lt;=( const path &amp; 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.&nbsp; For example, on Windows, the follow must succeed:</p>
<blockquote>
<pre>path p( &quot;c:&quot;, system_specific );
p &lt;&lt;= path( &quot;/foo&quot;, system_specific );
assert( p.generic_path() == &quot;c:/foo&quot; );</pre>
</blockquote>
</blockquote>
<h3><a name="operator-shift">operator &lt;&lt;</a></h3>
<blockquote>
<pre>const path operator&lt;&lt; ( const path &amp; rhs ) const;</pre>
<p><b>Returns:</b> <code>path( *this ) &lt;&lt;= rhs</code></p>
<p><b>Rationale:</b> Operator &lt;&lt; is supplied, because it, together with operator &lt;&lt;=, provides a
convenient way for users to supply paths with a variable number of elements.&nbsp;
For example, <code>initial_directory() &lt;&lt; &quot;src&quot; &lt;&lt; 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&lt;&lt;</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 &amp; 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 &quot;/&quot;, a name &quot;..&quot;, 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 &amp; 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 &amp; 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 &amp;</code> to give implementations freedom to avoid&nbsp; 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() &lt;= 1 ? path(&quot;&quot;) : 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 &amp;</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&lt;&lt;</a></h3>
<blockquote>
<p><code>const path operator &lt;&lt; ( const char * lhs, const path &amp; rhs );<br>
const
path operator &lt;&lt; ( const std::string &amp; lhs, const path &amp; rhs );</code></p>
<p><b>Returns:</b> <code>path( lhs ) &lt;&lt;= 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
View 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.&nbsp; 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.&nbsp; 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">&nbsp;</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">&nbsp;</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">&nbsp;</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">&nbsp;</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 &quot;Foo&quot; and &quot;foo&quot;. </td>
<td valign="top">&nbsp;</td>
<td valign="top">Some filesystems are case insensitive.&nbsp; 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.&nbsp; For example, do not expect a file
created with the name of &quot;Foo&quot; to be open successfully with the name of &quot;foo&quot;.</td>
<td valign="top">&nbsp;</td>
<td valign="top">Some filesystems are case sensitive.&nbsp; 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.&nbsp;
Note that ISO 9660 level 1 has an explicit directory tree depth limit of 8.</td>
<td valign="top">&nbsp;</td>
<td valign="top">Some operating systems place limits on the total path length.&nbsp; 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.&nbsp; Pick the specific limit according to
the operating systems you wish portability to:<br>
&nbsp; Greater than 31 characters:&nbsp; POSIX, Windows, MAC OS X.<br>
&nbsp; 31 characters: Classic Mac OS<br>
&nbsp; 8 characters + period + 3 characters: ISO 9660 (CD-ROM)<br>
<strong>...</strong></td>
<td valign="top">&nbsp;</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>

View 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

View 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

View 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

View 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

View 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
View 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
View 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

View 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
View 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
View 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
View 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
View 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
View 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;
}

View 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;
}