From 5abb500a29ec84d2c8e95ddfc19ca7cf39df3c4b Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 28 Apr 2024 23:48:49 +0300 Subject: [PATCH] Rewritten documentation in QuickBook and Doxygen. --- bug/bug.cpp | 10 +- bug/index.html | 13 - doc/.gitignore | 2 + doc/Jamfile.v2 | 151 +- doc/acknowledgements.qbk | 137 + doc/cautions.qbk | 60 + doc/changelog.qbk | 612 ++ doc/deprecated.qbk | 225 + doc/design.qbk | 243 + doc/faq.qbk | 116 + doc/filesystem.qbk | 49 + doc/install.qbk | 216 + doc/intro.qbk | 77 + doc/issue_reporting.qbk | 194 + doc/portability_guide.qbk | 205 + doc/reference-full.qbk | 9030 +++++++++++++++++ doc/reference.qbk | 27 + doc/relative_proposal.qbk | 964 ++ doc/tutorial.qbk | 835 ++ doc/v3.qbk | 197 + doc/v4.qbk | 71 + example/path_info.cpp | 93 +- example/tut0.cpp | 6 +- example/tut1.cpp | 6 +- example/tut2.cpp | 13 +- example/tut3.cpp | 17 +- example/tut4.cpp | 19 +- example/tut5.cpp | 2 + include/boost/filesystem/config.hpp | 20 + .../boost/filesystem/detail/path_traits.hpp | 144 +- include/boost/filesystem/directory.hpp | 13 +- include/boost/filesystem/operations.hpp | 29 +- include/boost/filesystem/path.hpp | 1790 +++- index.html | 4 +- src/path.cpp | 16 +- 35 files changed, 15168 insertions(+), 438 deletions(-) delete mode 100644 bug/index.html create mode 100644 doc/.gitignore create mode 100644 doc/acknowledgements.qbk create mode 100644 doc/cautions.qbk create mode 100644 doc/changelog.qbk create mode 100644 doc/deprecated.qbk create mode 100644 doc/design.qbk create mode 100644 doc/faq.qbk create mode 100644 doc/filesystem.qbk create mode 100644 doc/install.qbk create mode 100644 doc/intro.qbk create mode 100644 doc/issue_reporting.qbk create mode 100644 doc/portability_guide.qbk create mode 100644 doc/reference-full.qbk create mode 100644 doc/reference.qbk create mode 100644 doc/relative_proposal.qbk create mode 100644 doc/tutorial.qbk create mode 100644 doc/v3.qbk create mode 100644 doc/v4.qbk diff --git a/bug/bug.cpp b/bug/bug.cpp index b36173118..2af60572d 100644 --- a/bug/bug.cpp +++ b/bug/bug.cpp @@ -1,5 +1,10 @@ +// Copyright Beman Dawes 2014 +// Distributed under the Boost Software License, Version 1.0. +// www.boost.org/LICENSE_1_0.txt +// // filesystem/bug/bug.cpp +//[bug_cpp #include #include @@ -13,7 +18,4 @@ int test_main(int, char*[]) // note name return ::boost::report_errors(); // required } - -// Copyright Beman Dawes 2014 -// Distributed under the Boost Software License, Version 1.0. -// www.boost.org/LICENSE_1_0.txt +//] diff --git a/bug/index.html b/bug/index.html deleted file mode 100644 index 985b9c0cc..000000000 --- a/bug/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - -Automatic redirection failed, please go to -../doc/issue_reporting.html. -
-

© Copyright Beman Dawes, 2014

-

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

- - diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 000000000..72eb5be7d --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1,2 @@ +html +*_reference.xml diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 06a615193..d62faeb18 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -1,23 +1,150 @@ -# Boost Filesystem Library Example Jamfile +# Copyright 2024 Andrey Semashev +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# https://www.boost.org/LICENSE_1_0.txt) -# Copyright Beman Dawes 2010 +using quickbook ; +using boostbook ; +using doxygen ; +using xsltproc ; -# Distributed under the Boost Software License, Version 1.0. -# See www.boost.org/LICENSE_1_0.txt +import set ; +import doxygen ; +import xsltproc ; +import notfile ; +import path ; +import project ; + +project boost/libs/filesystem/doc ; + +local doxygen_params = + RECURSIVE=YES + ALPHABETICAL_INDEX=YES + REPEAT_BRIEF=YES + ALWAYS_DETAILED_SEC=YES + BRIEF_MEMBER_DESC=NO + ABBREVIATE_BRIEF=YES + INHERIT_DOCS=YES + HIDE_UNDOC_MEMBERS=YES + HIDE_UNDOC_CLASSES=YES + HIDE_SCOPE_NAMES=YES + AUTOLINK_SUPPORT=YES + DISTRIBUTE_GROUP_DOC=NO + SUBGROUPING=NO + EXTRACT_ALL=NO + EXTRACT_PRIVATE=NO + BUILTIN_STL_SUPPORT=YES + ENABLE_PREPROCESSING=YES + MACRO_EXPANSION=YES + SHORT_NAMES=YES + TAB_SIZE=4 + SOURCE_BROWSER=YES + VERBATIM_HEADERS=NO +# SEARCH_INCLUDES=YES +# "INCLUDE_PATH=../../.." +# EXCLUDE_SYMBOLS="detail detail::*" + "PREDEFINED=BOOST_FILESYSTEM_DOXYGEN \\ + BOOST_FILESYSTEM_DECL= \\ + BOOST_FILESYSTEM_DETAIL_DOC_ALT(alt, ...)=alt \\ + BOOST_FILESYSTEM_DETAIL_DOC_HIDDEN(...)=... \\ + BOOST_FILESYSTEM_DETAIL_DOC(...)=__VA_ARGS__ \\ + BOOST_NO_CXX17_DEDUCTION_GUIDES=1 \\ + BOOST_BITMASK(x)= \\ + BOOST_SYMBOL_VISIBLE= \\ + BOOST_FORCEINLINE=inline \\ + BOOST_INLINE_VARIABLE=inline \\ + BOOST_NOEXCEPT=noexcept \\ + BOOST_CONSTEXPR=constexpr \\ + BOOST_CXX14_CONSTEXPR=constexpr" + boost.doxygen.detailns=detail +# boost.doxygen.detail=implementation_ + ; + + +doxygen path_reference + : + ../../../boost/filesystem/path.hpp + : + $(doxygen_params) + "boost.doxygen.reftitle=Path Reference" + "boost.doxygen.refid=path" + ; + +doxygen operations_reference + : + ../../../boost/filesystem/operations.hpp + : + $(doxygen_params) + "boost.doxygen.reftitle=Filesystem Operations" + "boost.doxygen.refid=operations" + ; -# Library home page: http://www.boost.org/libs/filesystem +doxygen directory_reference + : + ../../../boost/filesystem/directory.hpp + : + $(doxygen_params) + "boost.doxygen.reftitle=Directory Iteration" + "boost.doxygen.refid=directory" + ; -project - : requirements - /boost/filesystem//boost_filesystem - static +doxygen file_status_reference + : + ../../../boost/filesystem/file_status.hpp + : + $(doxygen_params) + "boost.doxygen.reftitle=File Status" + "boost.doxygen.refid=file_status" ; -exe path_table : path_table.cpp ; -install path_table-copy : path_table : . ; +doxygen exception_reference + : + ../../../boost/filesystem/exception.hpp + : + $(doxygen_params) + "boost.doxygen.reftitle=Exceptions" + "boost.doxygen.refid=exceptions" + ; + +doxygen io_reference + : + ../../../boost/filesystem/cstdio.hpp + ../../../boost/filesystem/fstream.hpp + : + $(doxygen_params) + "boost.doxygen.reftitle=I/O Utilities" + "boost.doxygen.refid=io_utilities" + ; + +xml filesystem_doc + : + filesystem.qbk + : + path_reference + operations_reference + directory_reference + file_status_reference + exception_reference + io_reference + ; + +boostbook filesystem + : + filesystem_doc + : + "boost.root=../../../.." + "boost.libraries=../../../libs/libraries.htm" + "nav.layout=none" + "boost.image=Boost" + "navig.graphics=1" + "chunk.section.depth=1" + "boost.compact.function=0" + pdf:"boost.url.prefix=https://www.boost.org/doc/libs/release/libs/filesystem/doc/html" + ; ############################################################################### alias boostdoc ; explicit boostdoc ; -alias boostrelease ; +alias boostrelease : filesystem ; explicit boostrelease ; diff --git a/doc/acknowledgements.qbk b/doc/acknowledgements.qbk new file mode 100644 index 000000000..df9d812fc --- /dev/null +++ b/doc/acknowledgements.qbk @@ -0,0 +1,137 @@ +[/ + / Copyright Andrey Semashev 2024. + / + / Distributed under the Boost Software License, Version 1.0. + / (See accompanying file LICENSE_1_0.txt or copy at + / https://www.boost.org/LICENSE_1_0.txt) + /] + +[section:acknowledgements Acknowledgements] + +[section:v1 Version 1] + +The Filesystem Library was designed and implemented by Beman Dawes. The original `directory_iterator` and `filesystem_error` classes +were based on prior work from Dietmar Kühl, as modified by Jan Langer. Thomas Witt was a particular help in later stages of initial +development. Peter Dimov and Rob Stewart made many useful suggestions and comments over a long period of time. Howard Hinnant helped +with internationalization issues. + +Key [link filesystem.design.requirements design requirements] and [link filesystem.design.realities design realities] were developed +during extensive discussions on the Boost mailing list, followed by comments on the initial implementation. Numerous helpful comments +were then received during the Formal Review. Participants included: + +* Aaron Brashears +* Alan Bellingham +* Aleksey Gurtovoy +* Alex Rosenberg +* Alisdair Meredith +* Andy Glew +* Anthony Williams +* Baptiste Lepilleur +* Beman Dawes +* Bill Kempf +* Bill Seymour +* Carl Daniel +* Chris Little +* Chuck Allison +* Craig Henderson +* Dan Nuffer +* Dan'l Miller +* Daniel Frey +* Darin Adler +* David Abrahams +* David Held +* Davlet Panech +* Dietmar Kühl +* Douglas Gregor +* Dylan Nicholson +* Ed Brey +* Eric Jensen +* Eric Woodruff +* Fedder Skovgaard +* Gary Powell +* Gennaro Prota +* Geoff Leyland +* George Heintzelman +* Giovanni Bajo +* Glen Knowles +* Hillel Sims +* Howard Hinnant +* Jaap Suter +* James Dennett +* Jan Langer +* Jani Kajala +* Jason Stewart +* Jeff Garland +* Jens Maurer +* Jesse Jones +* Jim Hyslop +* Joel de Guzman +* Joel Young +* John Levon +* John Maddock +* John Williston +* Jonathan Caves +* Jonathan Biggar +* Jurko +* Justus Schwartz +* Keith Burton +* Ken Hagen +* Kostya Altukhov +* Mark Rodgers +* Martin Schuerch +* Matt Austern +* Matthias Troyer +* Mattias Flodin +* Michiel Salters +* Mickael Pointier +* Misha Bergal +* Neal Becker +* Noel Yap +* Parksie +* Patrick Hartling +* Pavel Vozenilek +* Pete Becker +* Peter Dimov +* Rainer Deyke +* Rene Rivera +* Rob Lievaart +* Rob Stewart +* Ron Garcia +* Ross Smith +* Sashan +* Steve Robbins +* Thomas Witt +* Tom Harris +* Toon Knapen +* Victor Wagner +* Vincent Finn +* Vladimir Prus +* Yitzhak Sapir + +A lengthy discussion on the C++ committee's library reflector illuminated the "illusion of portability" problem, particularly in +postings by PJ Plauger and Pete Becker. + +Walter Landry provided much help illuminating symbolic link use cases for version 1.31.0. + +[endsect] + +[section:v2 Version 2] + +So many people have contributed comments and bug reports that it isn't any longer possible to acknowledge them individually. That said, +Peter Dimov and Rob Stewart need to be specially thanked for their many constructive criticisms and suggestions. Terence Wilson and +Chris Frey contributed timing programs which helped illuminate performance issues. + +[endsect] + +[section:v3 Version 3] + +Peter Dimov suggested the idea of a single path class that could cope with multiple character types and encodings rather than +a `basic_path` class template. That idea was the basis for the Version 3 redesign. Walter Landry contributed both the design +and implementation of the `copy_any`, `copy_directory`, `copy_symlink`, and `read_symlink` functions. + +Thanks for comments from Robert Stewart, Zach Laine, Peter Dimov, Gregory Peele, Scott McMurray, John Bytheway, Jeff Flinn, +Jeffery Bosboom. + +[endsect] + +[endsect] diff --git a/doc/cautions.qbk b/doc/cautions.qbk new file mode 100644 index 000000000..32d6dcaee --- /dev/null +++ b/doc/cautions.qbk @@ -0,0 +1,60 @@ +[/ + / Copyright Andrey Semashev 2024. + / + / Distributed under the Boost Software License, Version 1.0. + / (See accompanying file LICENSE_1_0.txt or copy at + / https://www.boost.org/LICENSE_1_0.txt) + /] + +[section:cautions Cautions] + +After reading the tutorial you can dive right into simple, script-like programs using +the Filesystem Library! Before doing any serious work, however, there a few cautions to be aware of. + +[section:fs_races Effects and Postconditions not guaranteed in the presence of race-conditions] + +Filesystem function specifications follow the C++ Standard Library form, specifying behavior in terms of +effects and postconditions. If a [link filesystem.reference.race_condition race-condition] exists, +a function's postconditions may no longer be true by the time the function returns to the +caller. + +The state of files and directories is often globally shared, and thus may be changed unexpectedly +by other threads, processes, or even other computers having network access to the filesystem. As an +example of the difficulties this can cause, note that the following asserts may fail: + +``` +assert(exists("foo") == exists("foo")); /*< This will fail if a non-existent "foo" comes into existence, or an + existent "foo" is removed, between the first and second call to `exists()`. + This could happen if, during the execution of the example code, another thread, + process, or computer is also performing operations in the same directory. */ + +remove_all("foo"); +assert(!exists("foo")); /*< This will fail if between the call to `remove_all()` and the call to + `exists()` a new file or directory named "foo" is created by another + thread, process, or computer. */ + +assert(is_directory("foo") == is_directory("foo")); /*< This will fail if another thread, process, or computer removes an + existing file "foo" and then creates a directory named "foo", between the + example code's two calls to `is_directory()`. */ +``` + +[endsect] + +[section:exceptions Exceptions] + +Unless otherwise specified, Boost.Filesystem functions throw +[link filesystem.reference.basic_filesystem_error-constructors `basic_filesystem_error`] +exceptions to report failures such as I/O errors. Implementations may also use C++ Standard Library +functions which can throw `std::bad_alloc` exceptions to report memory allocation errors. These exceptions +may be thrown even though the error condition leading to the exception is not explicitly specified in +the function's "Throws" paragraph. + +Nominally non-throwing versions are provided for [link filesystem.reference.operational-functions operational functions] +that access the external file system, since these are often used in contexts where error codes may be +the preferred way to report an error. Even the nominally non-throwing versions of functions will throw +`std::bad_alloc` exceptions to report memory allocation errors. However, functions marked `noexcept` never +throw exceptions. + +[endsect] + +[endsect] diff --git a/doc/changelog.qbk b/doc/changelog.qbk new file mode 100644 index 000000000..c7e793cba --- /dev/null +++ b/doc/changelog.qbk @@ -0,0 +1,612 @@ +[/ + / Copyright Andrey Semashev 2024. + / + / Distributed under the Boost Software License, Version 1.0. + / (See accompanying file LICENSE_1_0.txt or copy at + / https://www.boost.org/LICENSE_1_0.txt) + /] + +[section:changelog Changelog] + +[heading 1.87.0] + +* Reworked documentation, converted to QuickBook and Doxygen. + +[heading 1.86.0] + +* `is_empty` operation is now better protected against concurrent filesystem modifications. +* On POSIX systems, `is_empty` now indicates error if invoked on a file other than a regular file or a directory. +* On Windows, fixed `file_size` and `is_empty` operating on symlinks rather than the files the symlinks refer to. ([github_issue 313]) +* `directory_entry::refresh` no longer throws an exception if the file referenced by the entry doesn't exist. This makes `directory_entry::status` and + `directory_entry::symlink_status`, as well as methods based on them, behave similarly to the equivalent standalone operations. The fact that the file + does not exist is still indicated via the `error_code` returned by the corresponding `directory_entry::refresh` overload, or can be seen by testing + if the file type returned by `directory_entry::status` or `directory_entry::symlink_status` calls is `file_type::file_not_found`. ([github_issue 314]) + +[heading 1.85.0] + +* `path::generic_path` and `path::generic_string` methods now remove duplicate directory separators in the returned paths. +* [*v4:] `path::generic_path`, `path::generic_string`, `path::make_preferred` and `path::lexically_normal` avoid converting between backslashes and forward slashes + in path root names. For example, on Windows, `path("\\\\?\\c:\\foo").generic_string()` now returns [^"\\\\?\\c:\/foo"] instead of [^"\/\/?\/c:\/foo"]. Similarly, + `path("\\\\host/share/foo/..").lexically_normal()` now returns [^"\\\\host\\share"]. +* [*v4:] `equivalent` now indicates error if either one of the paths doesn't exist. +* [*v4:] `absolute` now returns a path with a trailing directory separator when the input path has an empty `relative_path()`. ([github_issue 301]) +* Added a `unique_path` overload taking a single `error_code& ec` argument. The overload generates a unique path using the default path model. +* `weakly_canonical` now produces an absolute path if the input path is relative and contains no elements that exist in the filesystem. ([github_issue 300]) +* Added a new `copy_options::ignore_attribute_errors` option for `copy_file` and `copy` operations. The new option allows to ignore possible errors while copying + file attributes. ([github_issue 179]) +* On Linux, `copy_file` backends based on `sendfile` and `copy_file_range` system calls will attempt to preallocate storage for the target file. This may reduce + filesystem fragmentation and provide early error indication if there is not enough free space. Not all filesystems support this feature; file copying proceeds + if storage preallocation is not supported. +* On POSIX systems that support [@https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdopendir.html `fdopendir`], `openat` and related APIs defined in + POSIX.1-2008, as well as on Windows, `recursive_directory_iterator` now uses file descriptors/handles instead of paths to query the file statuses and open nested + directories during iteration. This makes directory iteration more resilient to concurrent modifications of the filesystem. +* Removed APIs that were previously declared deprecated. In particular, `path` and `recursive_directory_iterator` member functions, `is_regular`, `copy_directory`, + `symbolic_link_exists`, `complete`, `copy_option`, `symlink_option`, as well as `boost/filesystem/convenience.hpp` and `boost/filesystem/path_traits.hpp` headers + were removed. Possible replacements for the removed components are mentioned in [link filesystem.deprecated.deprecated-names Deprecated names and features] section. +* Support for `path` construction, assignment and appending from container types (e.g. `std::vector`) is now disabled by default. Users can still enable this + functionality by defining `BOOST_FILESYSTEM_DEPRECATED`. This functionality remains deprecated and will be completely removed in a future release. + +[heading 1.84.0] + +* As was announced in Boost 1.82.0, C++03 is no longer supported. A C++11 or later compiler is required. +* Fixed that some `directory_entry` observers taking `error_code& ec` argument did not clear the error code on successful return. ([github_issue 291]) +* On Windows, improved robustness of date and time conversion and added support for dates before January 1, 1970. ([github_issue 293]) +* Removed support for Windows CE that was deprecated since Boost.Filesystem 1.79.0. +* Removed `boost/filesystem/string_file.hpp` header. The header was deprecated since Boost.Filesystem 1.79.0. +* [*Deprecated:] Support for Windows versions older than Windows 10 is deprecated and will be removed in Boost 1.87. + +[heading 1.83.0] + +* Added `directory_entry::refresh` method that updates internal cached file statuses for the directory entry identified by path. +* [*v4:] `directory_entry` constructors and modifiers that initialize or modify the path now automatically call `refresh`. This may result in errors + that were not indicated before and in [*v3], if querying the filesystem for file statuses fails (e.g. if the file does not exist). This new behavior + is similar to `std::filesystem`. +* [*v4:] `directory_entry` constructors and methods taking `file_status` parameters are removed. Users are recommended to remove these arguments and rely + on `directory_entry` calling `refresh` internally. +* Added `directory_entry` member methods for checking the file type of the file, similar to `std::filesystem`. +* Added more methods for testing file status: `is_block_file`, `is_character_file`, `is_fifo`, `is_socket` and `is_reparse_file`. +* `recursive_directory_iterator` is now more likely to reuse information about the file type that is obtained during filesystem iteration. This may improve + performance. ([github_issue 288]) +* File streams defined in `boost/filesystem/fstream.hpp` are now movable, if the standard library file streams are. ([github_issue 280]) +* Added a new header `boost/filesystem/cstdio.hpp` with a portable `fopen` overload that takes `path` as the first argument. This function is equivalent to + `std::fopen`, except that on Windows it uses the native wide character encoding for paths. +* Generic `path` comparison operators are now more restricted to avoid potential ambiguities when user's code contains a `using namespace boost::filesystem;` + directive. ([github_issue 285]) +* Fixed potential overload resolution ambiguity in users' code, where `path` constructors from iterators could interfere with function overloads taking a + `std::initializer_list` argument. ([github_issue 287]) +* On Windows, added more workarounds for errors returned by various filesystems when creating a directory iterator. ([github_issue 284], [github_issue 286]) +* On Windows, relaxed access rights needed for querying file times. ([github_issue 290]) + +[heading 1.82.0] + +* Due to changes in Boost.System and some other libraries used in Boost.Filesystem, the support for C++03 is deprecated. C++11 will become the minimum + starting with Boost.Filesystem 1.84. +* Fixed compilation errors that could have been caused by `path` conversion constructors being too permissive on the accepted arguments. + ([github_issue 273]) +* [*v4:] `path::remove_filename` now presesrves the trailing directory separator. ([github_issue 271]) +* Added `path::remove_filename_and_trailing_separators`, which removes the filename and directory separators preceding it from the path. This behavior + is similar to `path::remove_filename` in Filesystem [*v3], but is also usable in [*v4]. +* Added `path::replace_filename`, which replaces filename in a path. +* Updated implementation of the library version selection to avoid ODR violations. ([github_issue 279]) +* On Windows, added a workaround for querying file attributes for files in SMBv1 shares. Previously, directories in SMBv1 shares could have been reported + as regular files. This does not affect SMBv2 or later. ([github_issue 282]) + +[heading 1.81.0] + +* [*Deprecated:] `path` construction, assignment and appending from containers of characters, such as `std::vector` or `std::list`, + is deprecated in [*v3] and removed in [*v4]. Please use string types or iterators instead. +* [*Deprecated:] `boost/filesystem/path_traits.hpp` header is deprecated and will be removed in a future release. The header contained implementation details + of `path` and should not be used in user's code. +* Previously deprecated APIs will now generate compilation warnings on use. To suppress these warnings, `BOOST_FILESYSTEM_ALLOW_DEPRECATED` macro can be + defined when compiling user's code. +* Fixed compilation due to a missing include on POSIX systems that do not support `*at` APIs. ([github_issue 250]) +* On Windows prior to 10, added a workaround for network share filesystem that produces `ERROR_INVALID_PARAMETER` when constructing directory iterators. + ([github_pr 246]) +* On Windows, fixed `weakly_canonical` failing with an `ERROR_INVALID_FUNCTION` error code if the path started with the [^"\\\\?\\"] prefix. + ([github_issue 247]) +* Added support for `std::string_view`, `boost::string_view` and `boost::container::string` (as well as respective `wchar_t` counterparts) in `path` + constructors, assignment and appending operations. ([github_issue 208]) +* `path` constructors, assignment and appending operations taking a pair of iterators will no longer accept iterators with value types that are not one of + the supported path character types. +* On Windows, improved compatibility of `directory_iterator` with various mounted filesystems and Wine releases prior to 7.21. + ([github_issue 255]) +* On Windows, deduplicated files are now reported as regular files rather than reparse files. ([github_issue 262]) + +[heading 1.80.0] + +* On Windows, added a fallback implementation for querying file attributes in case if the file cannot be opened with `ERROR_ACCESS_DENIED` error. This may allow + `status` and `symlink_status` to succeed for system files and directories that are not reparse points or symlinks. ([github_issue 234]) +* On Windows, added a workaround for FAT\/exFAT filesystems that produce `ERROR_INVALID_PARAMETER` when querying file attributes. This affected `status` and + `symlink_status`, which reported that files do not exist, and directory iterators, which failed to construct, as well as other dependent operations. + ([github_issue 236]) +* Worked around a compilation problem on [@https://www.rtems.org/ RTEMS]. ([github_pr 240]) +* On Linux, corrected switching to `sendfile` `copy_file` implementation if `copy_file_range` failed with `ENOSYS` in runtime. The `sendfile` fallback + implementation used to skip the filesystem type check and could fail for some filesystems. +* On POSIX systems supporting `openat` and related APIs defined in POSIX.1-2008 and on Windows Vista and later, improved protection of `remove_all` against + [@https://www.cve.org/CVERecord?id=CVE-2022-21658 CVE-2022-21658] that was implemented in the previous release. The previous fix could still result in removing + unintended files in [@https://github.com/boostorg/filesystem/issues/224#issuecomment-1183738097 certain conditions]. Other systems remain vulnerable. + +[heading 1.79.0] + +* [*v3:] `path::replace_extension` now works in terms of [*v3] definition of `path::extension` rather than [*v4]. +* Fixed compilation of path appending and concatenation operators with arguments of types convertible to `path` or compatible string type. ([github_issue 223]) +* On POSIX systems that support [@https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdopendir.html `fdopendir`] and + [@https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html `O_NOFOLLOW`] and on Windows, `remove_all` is now protected against + [@https://www.cve.org/CVERecord?id=CVE-2022-21658 CVE-2022-21658]. The vulnerability is a race condition that allows a third party process to replace + a directory that is being concurrently processed by `remove_all` with a directory symlink and cause `remove_all` to follow the symlink and remove files + in the linked directory instead of removing the symlink itself. ([github_issue 224]) +* On Windows, in `remove` and `remove_all` implementation, use POSIX semantics for file removal, when supported by the OS (Windows 10 1709 and later). + When POSIX semantics is supported, the file name is removed from the filesystem namespace as soon as the file is marked for deletion, even if it is still + open and in use. With legacy Windows semantics, the file name remains present in the the filesystem namespace until the last file handle to the file is closed, + which allows the file marked for deletion to be opened and prevents creating new files with the same name. ([github_issue 216]) +* On Windows, `remove` and `remove_all` now support deleting read-only directories. Support for removing read-only non-directory files was added previously. +* On Windows, `directory_iterator` internal implementation has been reworked to better utilize modern Windows APIs, which may improve performance while + handling symlinks. +* On Windows, initialize internal WinAPI function pointers early, if possible, to allow Boost.Filesystem operations to be invoked in global constructors. This is + only supported on MSVC, GCC, Clang and compatible compilers. +* On Windows, `resize_file` should no longer fail with an error if the file to be resized is opened. +* Disabled use of the `statx` syscall on Android prior to 11.0 (API version 30). The syscall is blacklisted by seccomp and causes process termination in runtime. + ([github_issue 229]) +* [*Deprecated:] `boost/filesystem/string_file.hpp` header is deprecated and will be removed in a future release. The header is no longer included by + `boost/filesystem.hpp` by default. Users are advised to implement the functionality themselves or migrate to other implementations. +* [*Deprecated:] Windows CE support is deprecated and will be removed in a future release. Windows CE has been untested for many years and is likely non-functional. + +[heading 1.78.0] + +* [*v4:] `path::filename` and `path::iterator` no longer return an implicit trailing dot ([^"."]) element if the path ends with a directory separator. Instead, + an empty path is returned, similar to C++17 std::filesystem. This also affects other methods that are defined in terms of iterators or filename, such as + `path::stem`, `path::compare` or `lexicographical_compare`. For example, `path("a/b/") == path("a/b/.")` no longer holds true. ([github_issue 193]) +* [*v4:] `path::lexically_normal` no longer produce a trailing dot ([^"."]) element and omits a directory separator after a trailing dot-dot ([^".."]) element + in the normalized paths. +* [*v4:] `path` append operations now consider root name and root directory in the appended path. If the appended path is absolute, or root name is present + and differs from the source path, the resulting path is equivalent to the appended path. If root directory is present, the result is the root directory and + relative path rebased on top of the root name of the source path. Otherwise, the behavior is similar to v3. ([github_issue 214]) +* `path::lexically_normal` now converts directory separators to preferred separators in the root name of the normalized paths. +* Optimized overloads of `path::assign`, `path::append`, `path::concat` and the corresponding operators to avoid unnecessary path copying and reduce + the amount of code redundancy. +* On POSIX systems, fixed `absolute(p, base)` returning a path with root name `base.root_name()` if `p` starts with a root directory. In such a case `p` + is already an absolute path and should be returned as is. +* `create_directories` no longer reports an error if the input path consists entirely of dot ([^"."]) and dot-dot ([^".."]) elements. The implementation is no longer + using recursion internally and therefore is better protected from stack overflow on extremely long paths. +* On Windows, `remove` now supports deleting read-only files. The operation will attempt to reset the read-only attribute prior to removal. Note that this + introduces a possibility of the read-only attribute being left unset, if the operation fails and the original value of the attribute fails to be restored. + This also affects `remove_all`. ([github_issue 216]) +* `remove_all` now returns `static_cast< uintmax_t >(-1)` in case of error, similar to C++17 std::filesystem. +* Fixed a linking error about unresolved references to Boost.ContainerHash functions when user's code includes `boost/filesystem/path.hpp` but not + `boost/container_hash/hash.hpp` and the compiler is set to preserve unused inline functions. ([github_issue 215]) +* Added a workaround for MSVC and compatible compilers eliminating path globals cleanup in release builds. This could lead to a memory leak if Boost.Filesystem + shared library was repeatedly loaded and unloaded in the process. ([github_issue 217]) + +[heading 1.77.0] + +[*Introducing Boost.Filesystem v4.] This new version of the library removes all deprecated features of v3 and also makes a number of breaking API changes intended +to make Boost.Filesystem more compatible with std::filesystem introduced in C++17 (original proposal: [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4099.html +ISO C++ File System Technical Specification]). The differences are described in the release notes and documentation using [*v3] and [*v4] tags and are also +summarised in a [link filesystem.v4 separate section]. Users can select Boost.Filesystem version by defining `BOOST_FILESYSTEM_VERSION` macro to either 3 or 4 +when compiling their code. + +There is no need to separately compile Boost.Filesystem for each library version — a single binary supports both v3 and v4. Users should avoid using both v3 and v4 +in the same application as this can lead to subtle bugs. + +Currently, v3 is the default. In a future release v4 will become the default, and eventually v3 will be removed. v4 is functional, but it is still a work in +progress and there may be breaking API changes in the future. + +Other changes in this release include: + +* [*v4:] `path::filename`, `path::stem` and `path::extension` no longer consider root name or root directory of the path as a filename if the path only consists + of those components. For example, on Windows `path("C:").filename()` used to return [^"C:"] and `path("C:\\").filename()` used to return [^"\\"] and both will return + an empty path now. ([github_issue 88]) +* [*v4:] `path::stem` and `path::extension` no longer treat a filename that starts with a dot and has no other dots as an extension. Filenames starting with a dot + are commonly treated as filenames with an empty extension. The leading dot is used to indicate a hidden file on most UNIX-like systems. + ([github_issue 88]) +* [*New:] Improved support for various path prefixes on Windows. Added support for local device prefix ([^"\\\\.\\"]) and experimental support for NT path prefix + ([^"\\??\\"]). The prefixes will be included in the root name of a path. Note that using the prefixes with Boost.Filesystem v3 can lead to surprising results + (e.g. `path("\\\\.\\").stem() == "\\\\"`). It is recommended to use the prefixes only with Boost.Filesystem v4. +* Reworked `path::lexically_normal` implementation to eliminate some cases of duplicate dot ([^"."]) elements in the normalized paths. +* [*New:] Added runtime detection of the `statx` and `getrandom` system calls on Linux. This can be useful if the syscall is present at compile time but fails + with `ENOSYS` at run time (for example, in Docker containers that restrict the syscall, even if available on the host). ([github_issue 172]) +* [*New:] Added support for disabling usage of various system APIs at library build time. This can be useful when a certain API is detected as present by + the library configuration scripts but must not be used for some reason (for example, when runtime detection does not work on the target system). See + the description of [link filesystem.install.config_macros configuration macros] for more details. +* [*New:] Added `copy_options::synchronize_data` and `copy_options::synchronize` options for the `copy_file` operation. These options allow to synchronize + the written data and attributes with the permanent storage. These options are expensive in terms of performance, but allow to ensure reliability of the copied + data. Note that `copy_file` performed implicit data synchronization on POSIX systems since Boost.Filesystem 1.74.0. This release adds support for more platforms + and disables data synchronization by default while allowing the caller to explicitly request it. ([github_issue 186]) +* Added handling of `EINTR` error code on POSIX systems for some system calls issued internally. In particular, `EINTR` could have been ignored on `close`, + which on HP-UX would result in a leaked file descriptor. +* In the `copy_file` implementations based on Linux `sendfile` and `copy_file_range` system calls, added handling of error codes indicating that a particular + filesystem does not support the system call and fall back to the generic `read`\/`write` loop. This should fix `copy_file` failing on [@https://www.ecryptfs.org/ + eCryptFS] and possibly other filesystems. ([github_issue 184]) +* The `copy_file_range` system call is now used since Linux kernel 4.5, whereas previously it was only enabled since 5.3. The `copy_file` implementation will + fall back to `sendfile` or `read`\/`write` loop if `copy_file_range` fails to copy a given file across filesystems. +* The `copy_file` implementations based on Linux `sendfile` and `copy_file_range` system calls will not be used on filesystems that are known to contain files + with generated content. These system calls are incompatible with such files, and copying them would result in zero-sized files. The generic `read`\/`write` + loop will be used instead. Currently, the blacklisted filesystems are: procfs, sysfs, tracefs and debugfs. +* In the `copy_file` implementation based on `read`\/`write` loop, increased the maximum size of the buffer used for temporary storage and take into account + the target filesystem block size for more optimal performance. +* On Windows CE, calling `current_path` to obtain the current path for a process will now fail with an error instead of returning successfully with a root path. + This platform does not support current directory. Changing the current path was already failing similarly in previous releases of Boost.Filesystem. +* In `canonical`, fixed the check for a symlink referencing a directory above root, if an earlier symlink was resolved to an absolute path with a different root + from the original path. +* In `canonical`, added a limit for the maximum number of symlinks that can be resolved during the call. The limit is currently at least 40 symlinks. +* On Windows, `canonical` and `weakly_canonical` will now use `path::preferred_separator` for the root directory separator in the resulting paths. This fixes + "file not found" errors caused by Windows API not handling generic separators in UNC paths and paths that start with the Win32 filesystem prefix ([^"\\\\?\\"]). + ([github_issue 87]) +* [*New:] Added `weakly_canonical` overloads taking `base` path as an argument. +* On Windows, `weakly_canonical` no longer fails with an error if the input path contains elements that do not exist in the filesystem but are cancelled by + a subsequent dot-dot ([^".."]) element. For example, `weakly_canonical("C:\\a\\..")` would previously fail if [^"C:\\a"] directory did not exist. + ([github_issue 201]) +* In `read_symlink` on Windows, corrected reparse point handling. The operation would return an empty path for some mount points (for example, created by + [@https://www.box.com/ Box] cloud storage driver) and directory junction points that had empty print names. The new implementation now parses substitute + name of the reparse point and attempts to reconstruct a Win32 path from it. ([github_issue 187]) +* On Windows, file streams provided in `boost/filesystem/fstream.hpp` will use wide character paths on libc++ versions 7.0 and higher, when the standard library + supports opening files with wide character paths. ([github_issue 181]) +* On Windows, creating symlinks should no longer require elevated privileges, if Windows is configured in + [@https://docs.microsoft.com/en-us/windows/apps/get-started/enable-your-device-for-development Developer mode]. +* With some compilers, global objects used internally in Boost.Filesystem are now destroyed after user's global destructors are called. This allows to call + Boost.Filesystem methods during the program termination stage. In particular, this concerns the path locale that is used for character code conversion + and can be installed by calling `path::imbue`. The supported compilers include MSVC, GCC and Clang, as well as other compilers that support customizing + program initialization order through `#pragma section` (for MSVC-compatible compilers) or `__attribute__ ((init_priority))` (for GCC-compatible compilers). + +[heading 1.76.0] + +* Updated compatibility with [@https://wasi.dev/ WASI] platform. ([github_pr 169]) +* Fixed an exception being thrown by `path::remove_filename` if the path is [^"\/\/\/\/"]. ([github_issue 176]) +* Fixed `create_directories` disregarding errors from file status query operations issued internally. This could result in incorrect error codes returned + by `create_directories`. ([github_issue 182]) + +[heading 1.75.0] + +* [*New:] Added `creation_time` operation, which allows to obtain file creation time. (Inspired by [github_pr 134]) +* The returned value of `last_write_time(p, ec)` operation in case of failure has been changed to a minimal value representable by `std::time_t` instead of -1. +* The returned value of `hard_link_count(p, ec)` operation in case of failure has been changed to `static_cast(-1)` instead of 0. +* On POSIX systems, `file_size` will now indicate error code `errc::function_not_supported` if the path resolves to a non-regular file. Previously, + `errc::operation_not_permitted` was reported. +* On Linux, many operations now use `statx` system call internally, when possible, which allows to reduce the amount of information queried from the filesystem + and potentially improve performance. The `statx` system call was introduced in Linux kernel 4.11. +* Removed `const`-qualification from return types of some `path` methods. This could prevent move construction and move assignment at the call site + in some cases. ([github_issue 160]) +* On OpenBSD 4.4 and newer, use `statvfs` system call to obtain filesystem space information. (Inspired by [github_pr 162]) +* On Windows, `space` now returns with an error if the provided path does not idendify an existing file. ([github_issue 167]) + +[heading 1.74.0] + +* Removed compile-time checks for support for symlinks and hardlink on Windows. Instead, a runtime check is used. ([github_pr 142]) +* Fixed handling of reparse points in `canonical` and `read_symlink` on Windows. This also affects other algorithms that involve `canonical` and `read_symlink` + in their implementation. ([github_pr 100], [github_issue 99]) +* Fixed that `read_symlink` on Windows could potentially fail or cause failures elsewhere with a sharing violation error, if the same symlink was opened + concurrently. ([github_issue 138]) +* Fixed that `is_symlink(directory_entry)` would always return `false`, even if the directory entry actually referred to a symlink. ([github_pr 148]) +* Added missing status inspection operation overloads for `directory_entry` and `error_code` (e.g. `is_directory(directory_entry, error_code&)`). + Removed incorrect `noexcept` specifications for the overloads not taking the `error_code` arguments. +* `copy_file` implementation has been updated to perform checks on the source and target files, as required by C++20 (\[fs.op.copy.file\]\/4.1). In particular, + the operation will fail if the source or target file is not a regular file or the source and target paths identify the same file. +* `copy_file` on POSIX systems will now also copy the source file permissions to the target file, if the target file is overwritten. +* [*New:] Added `copy_file` implementations based on `sendfile` and `copy_file_range` system calls on Linux, which may improve file copying performance, + especially on network filesystems. +* [*Deprecated:] The `copy_option` enumeration that is used with the `copy_file` operation is deprecated. As a replacement, the new enum `copy_options` + (note the trailing 's') has been added. The new enum contains values similar to the `copy_options` enum from C++20. The old enum values are mapped onto + the new enum. The old enum will be removed in a future release. +* [*New:] Added `copy_options::skip_existing` option, which allows `copy_file` operation to succeed without overwriting the target file, if it exists. +* [*New:] Added `copy_options::update_existing` option, which allows `copy_file` operation to conditionally overwrite the target file, if it exists, if + its last write time is older than that of the replacement file. +* [*New:] `copy_file` now returns `bool`, which indicates whether the file was copied. +* [*New, breaking change:] `copy` operation has been extended and reworked to implement behavior specified in C++20 \[fs.op.copy\]. This includes support + for `copy_options::recursive`, `copy_options::copy_symlinks`, `copy_options::skip_symlinks`, `copy_options::directories_only`, `copy_options::create_symlinks` + and `copy_options::create_hard_links` options. The operation performs additional checks based on the specified options. Applying `copy` to a directory with + default `copy_options` will now also copy files residing in that directory (but not nested directories or files in those directories). +* [*New:] Added `create_directory` overload taking two paths. The second path is a path to an existing directory, which is used as a source of permission + attributes to use in the directory to create. +* [*Deprecated:] `copy_directory` operation has been deprecated in favor of the new `create_directory` overload. Note that the two operations have reversed order + of the path arguments. +* `equivalent` on POSIX systems now returns the actual error code from the OS if one of the paths does not resolve to a file. Previously the function would return + an error code of 1. ([github_issue 141]) +* `equivalent` no longer considers file size and last modification time in order to test whether the two paths refer to the same file. These checks could result + in a false negative if the file was modified during the `equivalent` call. +* [*New:] Added `absolute` overloads taking `error_code` argument. +* Operations that have `current_path()` as the default value of their arguments and also have an `error_code` argument will use the `current_path(error_code& ec)` + overload to obtain the current path, so that its failure is reported via the `error_code` argument instead of an exception. +* `space` now initializes the `space_info` structure members to -1 values on error, as required by C++20 (\[fs.op.space\]\/1). +* `space` on Windows now accepts paths referring to arbitrary files, not only directories. This is similar to POSIX systems and corresponds to the operation + description in C++20. ([github_issue 73]) +* [*New:] Added implementation of `temp_directory_path` for Windows CE. ([github_pr 25]) +* [*New:] Improved compatibility with [@https://wasi.dev/ WASI] platform. ([github_pr 144]) +* [*New:] Improved support for Embarcadero compilers. ([github_pr 130]) +* [*New:] Added implementations of `unique_path` operation based on `getrandom` (Linux), `arc4random_buf` (OpenBSD\/FreeBSD\/CloudABI) and BCrypt (Windows) system APIs. +* [*Deprecated:] Auto-linking against system libraries on Windows with MSVC-compatible compilers is deprecated and will be removed in a future release. This + affects users linking against static library of Boost.Filesystem. Users are advised to update their project build systems to either use a shared library of + Boost.Filesystem, or explicitly specify the dependencies of Boost.Filesystem in the linker command line. In the future, the dependency information may also be + exposed through CMake config files. + +[heading 1.72.0] + +* Extracted `filesystem_error` to `exception.hpp`; `file_status` and associated enums and functions to `file_status.hpp`; `directory_entry`, `directory_iterator` + and `recursive_directory_iterator` to `directory.hpp`. +* [*Deprecated:] For backward compatibility `operations.hpp` still includes the new headers `exception.hpp`, `file_status.hpp` and `directory.hpp`, unless + `BOOST_FILESYSTEM_NO_DEPRECATED` macro is defined. These implicit includes are considered deprecated and will be removed in a future release. Users are encouraged + to include the new headers directly or include `filesystem.hpp`. +* The `filesystem_error` exception is now implemented in the compiled library of Boost.Filesystem. Users may need to add linking with Boost.Filesystem library + in their projects. +* On POSIX.1-2008 platforms, use `utimensat` instead of `utime`. `utime` is declared obsolete in POSIX.1-2008 and can be disabled e.g. in uClibc-ng. ([github_pr 115]) +* `directory_iterator` is now left in the end state on memory allocation errors. +* In `directory_iterator` on POSIX systems, support for `readdir`\/`readdir_r` has been reworked to avoid memory allocations for `dirent` structures when `readdir` + is used. This reduces memory consumption and eliminates the possibility of buffer overruns in case if `readdir` produces a very long directory name. +* On Windows, use Boost.WinAPI to select the target Windows version. +* [*New:] Added `directory_options` enum, which reflects the same named enum from C++20. The enum is supported in `directory_iterator` and `recursive_directory_iterator` + to customize iteration behavior. In particular, the iterators now support skipping directories that can't be opened due to insufficient permissions. + The `symlink_option` enum is now deprecated and should be replaced with `directory_options`. +* By default, `recursive_directory_iterator` is now reset to the end state in case of errors, as required by C++20. ([github_issue 112]) +* [*New:] Added `directory_options::pop_on_error` option, which configures `recursive_directory_iterator` so that it attempts to recover from iteration errors + by repeatedly invoking `pop()` until it succeeds or the end state is reached. ([github_issue 113]) +* [*New:] Added `directory_options::skip_dangling_symlinks` option, which configures `recursive_directory_iterator` so that it doesn't follow dangling directory + symlinks and continues iteration instead of reporting an error. +* [*Deprecated:] The following members of `recursive_directory_iterator` are now marked as deprecated: `level()`, `no_push_pending()`, `no_push_request()`, `no_push()`. + Users are advised to replace their use with the standard counterparts: `depth()`, `recursion_pending()`, `disable_recursion_pending()`. Note that + `recursion_pending()` has the opposite meaning compared to `no_push_pending()` and `no_push_request()`. Deprecated methods will be removed in a future release. +* Fixed `path::lexically_relative` (and any dependent algorithms) to correctly handle empty, dot and dot-dot path elements in its argument. The behavior is made + closer to C++17 `std::path::lexically_relative` in that empty and dot path elements are ignored and dot-dot path elements are accounted by decreasing the number + of dot-dot path elements to generate in the resulting relative path. ([github_issue 76]) + +[heading 1.71.0] + +* [*New:] Added minimal support for CMake. ([github_pr 106]) +* Fixed incorrect `error_code` returned from directory iterator increment when `readdir_r` is used. +* For `path`, fixed rvalue-aware `operator/` return type to return an rvalue instead of rvalue reference. This fixes leaving a dangling reference in the user's code + if the result of `operator/` is bound to a const reference. ([github_issue 110]) +* Fixes for better compatibility with Windows CE. ([github_pr 24]) + +[heading 1.70.0] + +* [*New:] Added support for movability to directory iterators. +* [*New:] Added file status query overloads for directory_entry. This avoids a relatively expensive OS query when file status is requested for a result of + dereferencing a directory iterator. ([github_pr 55]) +* Fixed a few instances of dereferencing `std::string::end()` in path implementation. +* Fixed program termination in case of out of memory condition in directory iterators constructors and operations accepting a reference to `error_code`. ([github_issue 58]) +* Fixed possible linking errors caused by missing definitions of static members of `path`. ([trac_issue 12759]) +* Fixed possible use of uninitialized data in directory iterator increment operation on Linux. ([github_issue 97]) +* Reworked `current_path` and `read_symlink` implementation to avoid possible memory exhaustion on broken or tampered with filesystems. The functions + now have an internal limit of the path size they will accept from the OS, which is currently 16 MiB. +* Increased the size of the internal buffer used by `copy_file`. + +[heading 1.69.0] + +* Don't use `readdir_r` on Linux and Android since the `readdir` function is already thread-safe. ([github_pr 68], [github_issue 72]) +* Fixed crashes in `boost::filesystem::copy` due to undefined behavior in the implementation. ([github_pr 71]) +* Fixed undefined behavior in `boost::filesystem::directory_iterator` implementation. ([github_pr 77]) +* Fixed compilation errors when using directory iterators with `BOOST_FOREACH`. +* Removed workarounds for older PGI C++ compiler versions to fix compilation on the newer ones. ([github_pr 49]) +* Fixed MSVC warnings about narrowing conversions. ([github_pr 44]) + +[heading 1.67.0] + +* Fix static initialization issue that caused a crash if path operations were used before main(). ([github_pr 62], [github_pr 43]) + +[heading 1.66.0] + +* Clean up some tutorial example code and fix the wording for it in the tutorial. Thanks to Anmol-Singh-Jaggi for pull request [github_pr 11]. + +[heading 1.64.0] + +* `is_empty()`overload with `error_code` parameter should not throw on error. Thanks to ldqrk for pull request [github_pr 42]. +* Fix [trac_issue 10731], ['Evaluate path.extension only once]. Thanks to Daniel Krügler for pull request [github_pr 41]. +* Fix error propagation in `space(p, ec)`. Thanks to cmuellner for pull request [github_pr 39]. +* Add `test/config_info.cpp` to increase macro state reporting in hopes of easing debugging on remote machines. +* Fix `operations_test` failure on MinGW: MinGW defines `__MINGW32__` rather than `_MSC_VER`, so also test for `__MINGW32__` to see if + `setenv`\/`unsetenv` workaround needed. + +[heading 1.63.0] + +* [*Deprecated `generic()` function name]: The undocumented experimental class `path` member function `generic()` has been renamed `generic_path()`. Fixes + [trac_issue 11855]. Unless the macro `BOOST_FILESYSTEM_NO_DEPRECATED` is defined, the original `generic()` will continue to be supplied as + a workaround for existing user code. But `generic()` is deprecated. User code should migrate to the new name. +* [*New:] Class `path` adds constexpr constants `separator` and `dot` of the type appropriate for the platform, and adds query functions + [link filesystem.reference.filename_is_dot `filename_is_dot`] and [link filesystem.reference.filename_is_dot_dot `filename_is_dot_dot`]. + These add convenience and the implementations may be more efficient that user coded equivalent functions. +* Fix [trac_issue 12578]. This bug in `directory_iterator` and `recursive_directory_iterator` equality testing has existed more than a dozen years. + Nowadays test driven development would likely have detected the problem in early development. Sigh. +* Fix [trac_issue 12495], from Samantha Ritter. Also affected `create_directory()`. Charles Olivi submitted a pull request with some particularly + helpful test cases. +* Fix [trac_issue 7307] This is a tough one to test. There are three internal function calls where errors might arise, and it would take too much time + to write tests for each of those cases. Someday we will have Titus Winter's mock installable file system, but for now are relying on code inspection + rather than testing. +* Fix a cygwin warning and a cygwin error. Thanks to thtrummer for pull request [github_pr 30]. +* Fixed two broken links in reference docs. Thanks to tbeu for pull request [github_pr 34]. +* Fix reference doc signatures for `path` member functions `stem()`, `extension()`. Thanks to faithandbrave for pull request [github_pr 31]. +* Fix broken link to [trac_issue 7506] in 1.60.0 Release History (Daniel Krügler). +* Refactor `push_directory()`internal logic so it is easier to reason about. + +[heading 1.60.0] + +* [*New:] Added functions [link filesystem.reference.lex-normal `lexically_normal`], [link filesystem.reference.lex-relative `lexically_relative`], + [link filesystem.reference.relative `relative`], and [link filesystem.reference.weakly_canonical `weakly_canonical`]. Many thanks to Jamie Allsop + for his help and perseverance. Resolves tickets [trac_issue 1976], [trac_issue 6249]. +* [*New:] Class `path` now has [link filesystem.reference.path-iterators `reverse_iterator`, `const_reverse_iterator`, `rbegin()`, and `rend()`]. +* [*New:] C++11 `noexcept` supplied as specified in the Filesystem TS if supported by the compiler. +* [*New:] C++11 move constructors and move assignments supplied as specified in the Filesystem TS if supported by the compiler. Resolves [trac_issue 10291]. +* [*New:] Existing functions whose names changed in the Filesystem TS are now supported under both the old and new names. +* [*New:] Added [link filesystem.reference.path-size `size()`] function to class `path`. Resolves [trac_issue 6874]. +* Clear several spurious GCC warnings. +* Fix [trac_issue 11733] by applying a patch from Idar Tollefsen. +* Fix a race condition in `unique_path` by applying [github_pr 15] from Sebastian Redl. Also fixes [trac_issue 7506], + ['`unique_path` Fails on Windows for Temporary User Profiles]. +* Fix bug in `file_status` and `recursive_directory_iterator`: C++ turns an explicit constructor with all arguments except first defaulted into + non-explicit single argument constructor. +* Fix [trac_issue 10591], by applying a patch submitted by Daniel Seither. +* Fix [trac_issue 9454] not compiling when `BOOST_FILESYSTEM_NO_DEPRECATED` is defined, by applying a patch submitted by Makesim. +* Fix [trac_issue 11447], by applying a patch submitted by Jasper Lievisse Adriaanse. +* Fix [trac_issue 11288], by applying a patch submitted by Yevhen Ivannikov. +* Fix [trac_issue 11175], out-of-date documentation causing users to incorrectly expect that the library could be used with exceptions disabled. +* Resolve [trac_issue 11175] by mitigating (i.e. reducing the likelihood of) a possible external file system race in `remove()`. +* Fix [trac_issue 7258]. Also fix related issues if path contains ['dot] or ['dot-dot] elements, and added test cases to the test suite. +* Reference docs editorial cleanups: Use same style sheet as the rest of the documentation. Tweak tab font size. Fix excessively long lines in + tables, synopsis. +* Resolve [trac_issue 10766], by adding examples and notes to the reference documentation to show why the returned value is in fact correct, + and to provide rationale for that behavior. See [link filesystem.reference.path-iterators \[path.itr\]], and + [link filesystem.reference.path-decomposition \[path.decompose\]] `parent_path()` and `filename()` sections of the reference docs. +* Minor other fixes, including pull requests from Jonathan Wakely and Marcel Raad. +* Closed several tickets as duplicates or otherwise resolved by the above changes: + * [trac_issue 7607] ['path should not infer an invisible [^"."] at the end of a path that ends with a slash] + * [trac_issue 7258] + * [trac_issue 11061] + * [trac_issue 11062] ['impossible to traverse the path of the reverse iterator]; this is effectively resolved by the addition of the class `path` + reverse iteration feature. The reference documentation has also been updated with [link filesystem.reference.path-iterators a note] warning + about the limitations of class `path` iterators. + +[heading 1.59.0] + +* Update the Tutorial: + * Use C++11 in the example programs to improve clarity. + * Update the example source code show to match the actual example source code in the cpp files. + * Rerun all the examples and update the output shown in the tutorial accordingly. + * Fix spacing and other HTML presentation issues. +* Fix [trac_issue 11491]. + +[heading 1.58.0] + +* Fix [trac_issue 6124], and [trac_issue 10038]. Cannot pass a `BOOST_SCOPED_ENUM` to a compiled function because it will result in an + undefined reference if the library is compiled with -std=c++0x but the use is compiled in C++03 mode, or visa versa. +* Rewrite Windows implementation of `temp_directory_path()` to (1) avoid `GetTempPath()` failure if path length > 130 (ticket [trac_issue 5300]) + and (2) provide a more sensible sequence of directories than provided by `GetTempPath()`, per boost list discussion "\[filesystem\] + temp_directory_path() behavior on Windows". The new sequence is: + # [^['%TMP%]] + # [^['%TEMP%]] + # [^['%LOCALAPPDATA%]\/Temp] + # [^['%USERPROFILE%]\/Temp] + # [^['`GetWindowsDirectoryW()`]\/Temp] + +[heading 1.57.0] + +* Rework class `path` locale and codecvt implementation for increased reliability. This change was SVN revision 83021, which should have gone into 1.56.0 + but unfortunately the merge didn't happen until too late. +* Fix tickets [trac_issue 8930], [trac_issue 9214], and [trac_issue 10641], all related to locales and `codecvt` facets. +* The net effect of the above changes and fixes should be to eliminate spurious "locale::facet::_S_create_c_locale name not valid" errors on Linux + and other non-BSD POSIX-like systems. The error will continue to occur, as it should, when a path encoding conversion `char`-to-`wchar_t` or + `wchar_t`-to-`char` is attempted in an environment without a valid C locale (for example, if the `LANG` environment variable is invalid or not defined). +* Fix [trac_issue 6124], and [trac_issue 10038] - an undefined reference that occurred when the library was compiled for C++03 but + the using program was compiled for C++11, or vice versa. The private library interface has been changed to use a plain-old C++03 enum. This is the fix + suggested by Andy in [trac_issue 6779]. +* The Windows implementation now treats NTFS directory junctions (also known as junctions, also known as mount points) as symlinks. This has the effect of + treating directory junctions as directories, and thus supporting all operations suitable for directories. This resolves [trac_issue 9016]. + Directory junctions are very similar to symlinks, but may have performance or other advantages in some situations. They can be created + from the command line with "[^mklink \/j link target]". There is no plan for Boost.Filesystem to be able to create them directly other than by calling + `std::system()`. + +[heading 1.56.0] + +* Reorganize `recursive_directory_iterator::increment`, adding an invariant that progress is always made, even if an error is reported by + exception or error_code. Add a manually executed test, `test/issues/recurse_dir_iter_5403.cpp`. Adjust regular regression tests as needed. + Thanks to Claudio Bley for the [github_pr 4] - the change was incorporated into the reorganized code. Fixes [trac_issue 5403]. +* Fix `canonical()` to treat parent of root as root. (Christian Hammerl) Fixes [trac_issue 9683] and [trac_issue 10187]. +* Added missing test for `__sun` macro which is defined on Solaris 10. (Chris Stylianou) +* Minor fixes and code cleanup. +* Update IDE projects to Visual Studio 2013. +* Remove unused `const char colon` to clear clang warning. (J?gen Hunold) +* Add BOOST_NOEXCEPT to `class filesystem_error`. +* Change `perms::all_all` and `perms::perms_mask` to absolute values to quiet intellisense warnings, and conform to C++11. + +[heading 1.54.0] + +* Reimplement `path::codecvt()` and `path::imbue()` with portable code that is intended to be much more robust and maintainable. A + section on [link filesystem.reference.path-Usage path usage concerns] has been added to the reference documentation describing several + concerns that arise in the context of multithreading and `path::codecvt()`. + +[heading 1.52.0] + +* Fix [trac_issue 7239]. The reported problem was a symptom of an internal bug that caused `path::filename()` and `path::parent_path()` + to fail on Windows for `path(":")`, and that in turn caused other functions that depend on `filename()` or `parent_path()` to fail, + such as `create_directories()`. + +[heading 1.51.0] + +* Add `begin()` and `end()` non-member functions for `directory_iterator` and `recursive_directory_iterator` so that C++11 range-based `for` + statements work. Suggested by feature requests [trac_issue 5896], using the [trac_issue 5896] approach. +* Add `range_begin()` and `range_end()` non-member functions for `directory_iterator` and `recursive_directory_iterator` so that + [@https://www.boost.org/libs/foreach/ `BOOST_FOREACH`] works. +* Fix a Linux `fchmodat` problem affecting symlink permissions reported during discussion of [trac_issue 6659]. +* Fix [trac_issue 6659], ['fchmodat supported only on Solaris 11]. Fix for both Sun and GCC compilers. + +[heading 1.50.0] + +* Remove Filesystem Version 2 from the distribution. Version 3 is now the only distributed version. Those still using V2 are urged + to migrate to V3 as soon as possible. +* Add `constexpr value_type preferred_separator` to class path. +* Fix [trac_issue 5118]. The documentation, implementation, and test cases have all had fixes applied. The documentation had failed + to mention that any existing extension is removed. The behavior for simple cases has been reverted to the Version 2 behavior, but + with corrections so that complex replacements now work. Two test cases from [trac_issue 5118] have been added. +* Fix [trac_issue 3737]. On Windows, `` is no longer included. +* Fix [trac_issue 4065]. This required multiple source code bug fixes and code cleanup, correcting problems not related to lexicographical issues. +* Add class path member function `compare` for consistency with `std::string`. +* Tighten `BOOST_FILESYSTEM_DYN_LINK` and `BOOST_FILESYSTEM_STATIC_LINK` logic in `filesystem/config.hpp` so that one or + the other is always defined, and both being defined is an `#error`. +* Fix [trac_issue 6690], resolving static linking related problems with VC++ 8 through 11. Note that this fix may reintroduce `codecvt` + thread safety problems [trac_issue 4889], for these compilers if static linking is used. +* Add `path::operator+=` and concat functions to tack on things like suffixes or numbers. Suggested by Ed Smith-Rowland and others. +* Fix [trac_issue 6809], by adding `MOVEFILE_COPY_ALLOWED` to deal with renames across drives, volumes, file systems. Fix has no effect + on non-Windows systems. +* Fix [trac_issue 6819], A path operand with a source that was a one character array was treated as empty, even if it wasn't empty. + Such arrays can occur in unions or in code using C variable length array idioms. +* Fix [trac_issue 6932]. + +[heading 1.49.0] + +* Fix [trac_issue 3714], added test cases and fixes for class path errors when assignment or append used self or portion of self as source. +* Fix [trac_issue 4889], ['Locale codecvt_facet not thread safe on Windows]. Move Windows, Mac OS X, `locale` and `codecvt` facet back to + namespace scope. POSIX except OS X uses local static initialization (i.e. lazy) to ensure exceptions are catchable if environmental variables + are misconfigured and to avoid use of `locale("")` if not actually used. +* Fix [trac_issue 5652]. Thanks to Daniel Aarno for the patch. +* Fix [trac_issue 5653]. +* Fix [trac_issue 5900]. Thanks to Andreas Eckleder for the patch. +* Fix [@https://svn.boost.org/trac/boost/ticket/5900#comment:2 #5900 comment 2], a bug in `director_iterator` construction with `error_code` + argument that caused increment to be called without the `ec` argument being passed. +* Fix [trac_issue 5900] by cleaning up test suite `path_test.cpp` code even though the ticket itself was not a defect, and clarifying docs; + iteration over a path yields generic format. +* Fix [trac_issue 5592]. +* Operations function fixes for PGI compiler, thanks to Noel Belcourt. +* Relax permissions test to reflect reality, particularly on the Sandia test platforms. + +[heading 1.48.0] + +* Added operational function [link filesystem.reference.canonical `canonical()`], suggested by David Svoboda, who also provided pseudo-code. +* Added [link filesystem.reference.hash_value `hash_value()`] function for paths. (Daniel James) +* Fix path inserter problem ([trac_issue 5764]) reported for QNX6.3.2 host (gcc-3.3.5) +* Fix problem of `locale("")` exception being thrown before `main()` starts on poorly configured (e.g. `LANG="bad name"`) POSIX systems. + Resolves the most serious aspect of tickets [trac_issue 4688], [trac_issue 5289]. + +[heading 1.47.0] + +* Program `file_status.cpp` added (V3). See [^['[*boost-root]]\/libs\/filesystem\/v3\/example]. Useful both as an example and to explore how + Boost.Filesystem treats various status errors. Run "[^bjam]" (NOT "[^bjam install]") in the example directory to install in [^example\/bin]. + +[heading 1.46.1] + +* Fix fstream problem for STLPort masquerading as Dinkumware ([trac_issue 5217]). + +[heading 1.46.0] + +* Version 3 of the library is now the default. +* IBM vacpp: Workaround for compiler bug affecting `iterator_facade`. ([trac_issue 4912]) +* Verify, clarify, document that `` can be used to specify `BOOST_FILESYSTEM_VERSION`. ([trac_issue 4891]) +* Replaced C-style `assert` with `BOOST_ASSERT`. +* Undeprecated `unique_path()`. Instead, add a note mentioning the workaround for lack of thread safety and possible change to cwd. + `unique_path()` is just too convenient to deprecate! +* Cleared several GCC warnings. +* Changed V2 code to use `BOOST_THROW_EXCEPTION`. +* Windows: Fix `status()` to report non-symlink reparse point correctly. +* Add `symlink_option` to `recursive_directory_iterator`, allowing control over recursion into directory symlinks. Note that the default + is changed to not recurse into directory symlinks. +* [link filesystem.reference Reference] documentation cleanup, including fixing missing and broken links, and adding missing functions. +* Miscellaneous implementation code cleanup. + +[heading:v3 Version 3] + +Boost 1.44.0 - June, 2010 - Internationalization via single class `path`. More uniform error handling. + +[heading:v2 Version 2] + +Boost 1.34.0 - May, 2007 - Internationalization via `basic_path` template. + +[heading:v1 Version 1] + +Boost 1.30.0 - March, 2003 - Initial official Boost release. + +[endsect] diff --git a/doc/deprecated.qbk b/doc/deprecated.qbk new file mode 100644 index 000000000..14237d910 --- /dev/null +++ b/doc/deprecated.qbk @@ -0,0 +1,225 @@ +[/ + / Copyright Andrey Semashev 2024. + / + / Distributed under the Boost Software License, Version 1.0. + / (See accompanying file LICENSE_1_0.txt or copy at + / https://www.boost.org/LICENSE_1_0.txt) + /] + +[section:deprecated Deprecated Features] + +As the library evolves over time, names sometimes change or old features are removed to make way for new features. To ease transition, +Boost.Filesystem deprecates the old names and features, but by default continues to provide many of them. The deprecated names and other +workarounds can be suppressed by defining macro `BOOST_FILESYSTEM_NO_DEPRECATED`, and this is recommended for all new code. + +In the table below, \u2714 indicates a synonym or other workaround is provided unless `BOOST_FILESYSTEM_NO_DEPRECATED` is defined. + +Additionally, when not disabled, most of the deprecated components will generate compilation warnings when used. These warnings are +intended to highlight the library usage that needs to be updated. For convenience during the transition period, these warnings can be +suppressed by defining `BOOST_FILESYSTEM_ALLOW_DEPRECATED` macro. + +[table Deprecated names and features +[[Component or location] [Old name, now deprecated] [\u2714] [New name]] +[[`class path`] +[ +Construction, assignment and appending from container types. +] +[] +[ +Use string types or iterators as the source for path construction, assignment and appending. +]] +[[`path.hpp`] +[ +``` +template +class basic_path; +``` +] +[] +[ +Class template `basic_path` is replaced by class `path`. No workaround for an explicitly coded `basic_path` is provided, but see the next +row - `path`. +]] +[[`path.hpp`] +[ +`typedef basic_path path` +] +[\u2714] +[ +`class path` +]] +[[`operations.hpp`] +[ +`initial_path()` +] +[\u2714] +[ +Function removed. Cache `current_path()` early in the application startup. +]] +[[Build system] +[ +Auto-linking on Windows +] +[] +[ +No longer supported. When users are linking against static library of Boost.Filesystem, they are recommended to explicitly add Boost.Filesystem +dependencies to their linker command line. Shared library of Boost.Filesystem is not affected by this as it is already linked with all its +dependencies. +]] +] + +Some library features were removed in one of the past releases. The table below lists some of those features along with suggested replacements. + +[table Removed names and features +[[Component or location] [Removed name] [Possible replacement]] +[[`class path`] +[`branch_path()`] +[`parent_path()`] +][ +[`class path`] +[`directory_string()`] +[`string`] +][ +[`class path`] +[`external_directory_string()`] +[`native()`] +][ +[`class path`] +[`external_file_string()`] +[`native()`] +][ +[`class path`] +[`file_string()`] +[`string()`] +][ +[`class path`] +[`has_branch_path()`] +[`has_parent_path()`] +][ +[`class path`] +[`has_leaf()`] +[`has_filename()`] +][ +[`class path`] +[`is_complete()`] +[`is_absolute()`] +][ +[`class path`] +[`leaf()`] +[`filename()`] +][ +[`class path`] +[`native_directory_string()`] +[`string()`] +][ +[`class path`] +[`native_file_string()`] +[`string()`] +][ +[`class path`] +[`normalize()`] +[Replace `p.normalize()` with `p = p.lexically_normal()`.] +][ +[`class path`] +[`remove_leaf()`] +[`remove_filename()`] +][ +[`path.hpp`] +[`typedef basic_path wpath`] +[`class path`] +][ +[`convenience.hpp`] +[`std::string extension(const path& p)`] +[Replace `extension(p)` with `p.extension().string()`.] +][ +[`convenience.hpp`] +[`std::string basename(const path& p)`] +[Replace `basename(p)` with `p.stem().string()`.] +][ +[`convenience.hpp`] +[`path change_extension(const path& p, const path& new_extension)`] +[Replace `path new_p = change_extension(p, ext);` with `path new_p = p; new_p.replace_extension(ext);`.] +][ +[`operations.hpp`] +[ +``` +template +Path complete(const Path& p, const Path& base=initial_path()) +``` +] +[`path absolute(const path& p, const path& base=current_path())`] +][ +[`operations.hpp`] +[`is_regular(file_status f)`] +[`is_regular_file(file_status f)`] +][ +[`operations.hpp`] +[`symbolic_link_exists(const path& ph)`] +[Replace `symbolic_link_exists(p)` with `is_symlink(symlink_status(p))`.] +][ +[`operations.hpp`] +[`copy_directory(const path& from, const path& to)`] +[`create_directory(const path& to, const path& from)`. Note the reversed order of arguments.] +][ +[`class directory_entry`] +[`filename()`] +[Replace `de.filename()` with `de.path().filename()`.] +][ +[`class directory_entry`] +[`leaf()`] +[Replace `de.leaf()` with `de.path().filename()`.] +][ +[`class directory_entry`] +[`string()`] +[Replace `de.string()` with `de.path().string()`.] +][ +[`class recursive_directory_iterator`] +[`level()`] +[`depth()`] +][ +[`class recursive_directory_iterator`] +[`no_push_pending()`] +[`!recursion_pending()`] +][ +[`class recursive_directory_iterator`] +[`no_push()`] +[`disable_recursion_pending()`] +][ +[`directory.hpp`] +[`enum class symlink_option`] +[Use corresponding values of `enum class directory_options` instead.] +][ +[`directory.hpp`] +[`wrecursive_directory_iterator` typedef] +[`class recursive_directory_iterator`.] +][ +[`operations.hpp`] +[ +The header provides `filesystem_error`, `file_status`, `directory_entry`, `directory_iterator`, `recursive_directory_iterator` and associated +enums and functions. +] +[Explicitly include headers `exception.hpp`, `file_status.hpp` and/or `directory.hpp` to introduce the required components.] +][ +[`path_traits.hpp`] +[The header contained implementation details of class `path`.] +[Remove the include.] +][ +[`convenience.hpp`] +[The header contained helper functions that were deprecated and then removed.] +[Remove the include.] +] +] + +[section:rationale Deprecation rationale] + +[section:initial_path `initial_path` function] + +Full implementation of `initial_path()` would require support from the C++ runtime startup code, and that doesn't seem likely to happen. +Depending on the user to call `initial_path()` at the beginning of `main()` is too error prone. An equivalent function can trivially be provided +by a user. + +[endsect] + +[endsect] + +[endsect] diff --git a/doc/design.qbk b/doc/design.qbk new file mode 100644 index 000000000..b566f887d --- /dev/null +++ b/doc/design.qbk @@ -0,0 +1,243 @@ +[/ + / Copyright Andrey Semashev 2024. + / + / Distributed under the Boost Software License, Version 1.0. + / (See accompanying file LICENSE_1_0.txt or copy at + / https://www.boost.org/LICENSE_1_0.txt) + /] + +[section:design Boost Filesystem Library Design] + +[section:introduction Introduction] + +The primary motivation for beginning work on the Filesystem Library was frustration with Boost administrative tools. Scripts were written in +Python, Perl, Bash, and Windows command languages. There was no single scripting language familiar and acceptable to all Boost administrators. +Yet they were all skilled C++ programmers - why couldn't C++ be used as the scripting language? + +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. + +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. + +[endsect] + +[section:requirements Requirements] + +* Be able to write portable script-style filesystem operations in modern C++. + + Rationale: This is a common programming need. It is both an embarrassment and a hardship that this is not possible with either the current + C++ or Boost libraries. The need is particularly acute when C++ is the only toolset allowed in the tool chain. File system operations are + provided by many languages used on multiple platforms, such as Perl and Python, as well as by many platform specific scripting languages. + All operating systems provide some form of API for filesystem operations, and the POSIX bindings are increasingly available even on + operating systems not normally associated with POSIX, such as the Mac, z\/OS, or OS\/390. + +* Work within the [link filesystem.design.realities realities] described below. + + 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. + +* Avoid dangerous programming practices. Particularly, all-too-easy-to-ignore error notifications and use of global variables. If a dangerous + feature is provided, identify it as such. + + Rationale: Normally this would be covered by "the usual Boost requirements...", but it is mentioned explicitly because the equivalent native + platform and scripting language interfaces often depend on all-too-easy-to-ignore error notifications and global variables like "current + working directory". + +* 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. + + Rationale: Much functionality which does not require a hierarchical directory structure is still useful on flat-structure filesystems. There + are many systems, particularly embedded systems, where even very limited functionality is still useful. + +* Interface smoothly with current C++ Standard Library input\/output facilities. For example, paths should be easy to use in `std::basic_fstream` + constructors. + + Rationale: One of the most common uses of file system functionality is to manipulate paths for eventual use in input\/output operations. + Thus the need to interface smoothly with standard library I\/O. + +* Suitable for eventual standardization. The implication of this requirement is that the interface be close to minimal, and that great care be + taken regarding portability. + + 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. + +* The usual Boost [@https://www.boost.org/more/lib_guide.htm requirements and guidelines] apply. + +* Encourage, but do not require, portability in path names. + + Rationale: For paths which originate from user input it is unreasonable to require portable path syntax. + +* Avoid giving the illusion of portability where portability in fact does not exist. + + Rationale: Leaving important behavior unspecified or "implementation defined" does a great disservice to programmers using a library because + it makes it appear that code relying on the behavior is portable, when in fact there is nothing 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. + +[endsect] + +[section:realities Realities] + +* Some operating systems have a single directory tree root, others have multiple roots. +* Some file systems provide both a long and short form of filenames. +* Some file systems have different syntax for file paths and directory paths. +* Some file systems have different rules for valid file names and valid directory names. +* Some file systems (ISO-9660, level 1, for example) use very restricted (so-called 8.3) file names. +* Some operating systems allow file systems with different characteristics to be "mounted" within a directory tree. Thus an ISO-9660 or Windows + file system may end up as a sub-tree of a POSIX directory tree. +* Wide-character versions of directory and file operations are available on some operating systems, and not available on others. +* There is no law that says directory hierarchies have to be specified in terms of left-to-right decent from the root. +* Some file systems have a concept of file "version number" or "generation number". Some don't. +* Not all operating systems use single character separators in path names. Some use paired notations. A typical fully-specified OpenVMS filename + might look something like this: + + [pre DISK$SCRATCH:\[GEORGE.PROJECT1.DAT\]BIG_DATA_FILE.NTP;5] + + The general OpenVMS format is: + + [pre Device:\[directories.dot.separated\]filename.extension;version_number] + +* For common file systems, determining if two descriptors are for same entity is extremely difficult or impossible. For example, the concept of + equality can be different for each portion of a path - some portions may be case or locale sensitive, others not. Case sensitivity is a property + of the pathname itself, and not the platform. Determining collating sequence is even worse. +* Race-conditions may occur. Directory trees, directories, files, and file attributes are in effect shared between all threads, processes, and + computers which have access to the filesystem. That may well include computers on the other side of the world or in orbit around the world. This + implies that file system operations may fail in unexpected ways. For example: + + ``` + assert(exists("foo") == exists("foo")); // may fail! + + assert(is_directory("foo") == is_directory("foo")); // may fail! + ``` + + In the first example, the file may have been deleted between calls to `exists()`. In the second example, the file may have been deleted and then + replaced by a directory of the same name between the calls to `is_directory()`. + +* 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. +* Symbolic links cause canonical and normal form of some paths to represent different files or directories. For example, given the directory + hierarchy [^"\/a\/b\/c"], with a symbolic link in [^"\/a"] named [^"x"] pointing to [^"b\/c"], then under POSIX Pathname Resolution rules a path + of [^"\/a\/x\/.."] should resolve to [^"\/a\/b"]. If [^"\/a\/x\/.."] were first normalized to [^"\/a"], it would resolve incorrectly. (Case + supplied by Walter Landry.) + +[endsect] + +[section:rationale Rationale] + +The [link filesystem.design.requirements Requirements] and [link filesystem.design.realities Realities] above drove much of the C++ interface design. +In particular, the desire to make script-like code straightforward caused a great deal of effort to go into ensuring that apparently simple +expressions like `exists("foo")` work as expected. + +See the [link filesystem.faq FAQ] for the rationale behind many detailed design decisions. + +Several key insights went into the `path` class design: + +* Decoupling of the input formats, internal conceptual (`vector` or other sequence) model, and output formats. +* Providing two input formats (generic and O\/S specific) broke a major design deadlock. +* Providing several output formats solved another set of previously intractable problems. +* Several non-obvious functions (particularly decomposition and composition) are required to support portable code. (Peter Dimov, Thomas Witt, Glen + Knowles, others.) + +Error checking was a particularly difficult area. One key insight was that with file and directory names, portability isn't a universal truth. +Rather, the programmer must think out the question "What operating systems do I want this path to be portable to?" By providing support for several +answers to that question, the Filesystem Library alerts programmers of the need to ask it in the first place. + +[endsect] + +[section:abandoned_designs Abandoned Designs] + +[section operations.hpp] + +Dietmar Kühl's original `directory_iterator` 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 [link filesystem.faq.wide-character_names FAQ]. + +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. + +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. + +Yet another set of convenience functions (for example, `remove` 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. + +[endsect] + +[section path.hpp] + +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. + +Additional design considerations apply to [link filesystem.v3.design Internationalization]. + +[endsect] + +[section Error checking] + +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. + +Some designs associated error checking mechanisms with paths. Some with operations functions. A policy-based error checking template design was +partially implemented, then abandoned as too complicated for everyday script-like programs. + +The final design, which depends partially on explicit error checking function calls, is much simpler and straightforward, although it does depend +to some extent on programmer discipline. But it should allow programmers who are concerned about portability to be reasonably sure that their +programs will work correctly on their choice of target systems. + +[endsect] + +[endsect] + +[section:references References] + +[variablelist +[ +[\[[#IBM-01]IBM-01\]] +[IBM Corporation, ['z\/OS V1R3.0 C\/C++ Run-Time Library Reference], SA22-7821-02, 2001, [@http://www-1.ibm.com/servers/eserver/zseries/zos/bkserv/ +www-1.ibm.com/servers/eserver/zseries/zos/bkserv/]] +] +[ +[\[[#ISO-9660]ISO-9660\]] +[International Standards Organization, 1988] +] +[ +[\[[#Kuhn]Kuhn\]] +[UTF-8 and Unicode FAQ for Unix\/Linux, [@https://www.cl.cam.ac.uk/~mgk25/unicode.html www.cl.cam.ac.uk/~mgk25/unicode.html]] +] +[ +[\[[#MSDN]MSDN\] ] +[Microsoft Platform SDK for Windows, Storage Start Page, [@http://msdn.microsoft.com/library/en-us/fileio/base/storage_start_page.asp +msdn.microsoft.com/library/en-us/fileio/base/storage_start_page.asp]] +] +[ +[\[[#POSIX-01]POSIX-01\]] +[IEEE Std 1003.1-2001, ISO\/IEC 9945:2002, and The Open Group Base Specifications, Issue 6. Also known as The Single UNIX® Specification, Version 3. +Available from each of the organizations involved in its creation. For example, read online or download from +[@http://www.unix.org/single_unix_specification/ www.unix.org/single_unix_specification/]. The ISO JTC1/SC22/WG15 - POSIX homepage is +[@https://www.open-std.org/jtc1/sc22/WG15/ www.open-std.org/jtc1/sc22/WG15/]] +] +[ +[\[[#URI]URI\]] +[RFC-2396, Uniform Resource Identifiers (URI): Generic Syntax, [@https://www.ietf.org/rfc/rfc2396.txt www.ietf.org/rfc/rfc2396.txt]] +] +[ +[\[[#UTF-16]UTF-16\]] +[Wikipedia, UTF-16, [@https://en.wikipedia.org/wiki/UTF-16 en.wikipedia.org/wiki/UTF-16]] +] +[ +[\[[#Wulf-Shaw-73]Wulf-Shaw-73\]] +[William Wulf, Mary Shaw, ['Global Variable Considered Harmful], ACM SIGPLAN Notices, 8, 2, 1973, pp. 23-34] +] +] + +[endsect] + +[endsect] diff --git a/doc/faq.qbk b/doc/faq.qbk new file mode 100644 index 000000000..603a74af0 --- /dev/null +++ b/doc/faq.qbk @@ -0,0 +1,116 @@ +[/ + / Copyright Andrey Semashev 2024. + / + / Distributed under the Boost Software License, Version 1.0. + / (See accompanying file LICENSE_1_0.txt or copy at + / https://www.boost.org/LICENSE_1_0.txt) + /] + +[section:faq Frequently Asked Questions] + +[section:general General questions] + +[heading Why not support a concept of specific kinds of file systems, such as posix_file_system or windows_file_system?] + +Portability is one of the most important requirements for the library. Features specific to a particular operating system +or file system can always be accessed by using the operating system's API. + +[endsect] + +[section:path Class `path` questions] + +[heading Why base the generic pathname format on POSIX?] + +[link filesystem.design.posix-01 POSIX] is an ISO Standard. It is the basis for the most familiar pathname formats, not just +for POSIX-based operating systems but also for Windows and the URL portion of URIs. It is ubiquitous and familiar. On many +systems, it is very easy to implement because it is either the native operating system format (Unix and Windows) or via an +operating system supplied POSIX library (z/OS, OS/390, and many more.) + +[heading Why not use a full URI (Universal Resource Identifier) based path?] + +[link filesystem.design.uri URIs] would promise more than the Filesystem Library can actually deliver, since URIs extend +far beyond what most operating systems consider a file or a directory. Thus for the primary "portable script-style file system +operations" requirement of the Filesystem Library, full URIs appear to be over-specification. + +[heading Why isn't `path` a base class with derived `directory_path` and `file_path` classes?] + +Why bother? The behavior of all three classes is essentially identical. Several early versions did require users to identify +each path as a file or directory path, and this seemed to increase coding errors and decrease code readability. There was no +apparent upside benefit. + +[heading Why do path decomposition functions yielding a single element return a path rather than a string?] + +Interface simplicity. If they returned strings, flavors would be needed for different string and character types. + +[heading Why don't `path` member functions have overloads with `error_code&` arguments?] + +They have not been requested by users; the need for error reporting via `error_code` seems limited to filesystem operation +failures rather than path failures. + +[endsect] + +[section:operations Operations function questions] + +[heading Why not supply a 'handle' type, and let the file and directory operations traffic in it?] + +It isn't clear there is any feasible way to meet the "portable script-style file system operations" requirement with such +a system. File systems exist where operations are usually performed on some non-string handle type. The classic Mac OS has been +mentioned explicitly as a case where trafficking in paths isn't always natural. + +The case for the "handle" (opaque data type to identify a file) style may be strongest for directory iterator value type. (See +Jesse Jones' Jan 28, 2002, Boost postings). However, as class `path` has evolved, it seems sufficient even as the directory +iterator value type. + +[heading Why are the operations functions so low-level?] + +To provide a toolkit from which higher-level functionality can be created. + +An extended attempt to add convenience functions on top of, or as a replacement for, the low-level functionality failed because +there is no widely acceptable set of simple semantics for most convenience functions considered. Attempts to provide alternate +semantics via either run-time options or compile-time polices became overly complicated in relation to the value delivered, +or became contentious. On the other hand, the specific functionality needed for several trial applications was very easy for +the user to construct from the lower-level toolkit functions. See [link filesystem.design.abandoned-designs Failed Attempts]. + +[heading Isn't it inconsistent then to provide a few convenience functions?] + +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()`. + +[heading Why are there `directory_entry` overloads for `operations.hpp` predicate functions? Isn't two ways to do the same +thing poor design?] + +Yes, two ways to do the same thing is often a poor design practice. But the `directory_entry` versions are often much more +efficient. Calling `status()` during iteration over a directory containing 15,000 files took 6 seconds for the path overload, +and 1 second for the `directory_entry` overload, for tests on a freshly booted machine. Times were .90 seconds and .30 seconds, +for tests after prior use of the directory. This performance gain is large enough to justify deviating from preferred design +practices. Neither overload alone meets all needs. + +[heading Why are the operations functions so picky about errors?] + +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 globally shared resources, and thus subject to race conditions. + +[heading Why are attributes accessed via named functions rather than property maps?] + +For commonly used attributes (existence, directory or file, emptiness), simple syntax and guaranteed presence outweigh other +considerations. Because access to many other attributes is inherently system dependent, property maps are viewed as the best hope +for access and modification, but it is better design to provide such functionality in a separate library. (Historical note: +even the apparently simple attribute "read-only" turned out to be so system dependent as to be disqualified as a "guaranteed +presence" operation.) + +[heading Why isn't automatic name portability error detection provided?] + +A number (at least six) of designs for name validity error detection were evaluated, including at least four complete +implementations. While the details for rejection differed, all of the more powerful name validity checking designs distorted +other otherwise simple aspects of the library. Even the simple name checking provided in prior library versions was a constant +source of user complaints. While name checking can be helpful, it isn't important enough to justify added a lot of additional +complexity. + +[heading Why are paths sometimes manipulated by member functions and sometimes by non-member functions?] + +The design rule is that purely lexical operations are supplied as class `path` member functions, while operations performed +by the operating system are provided as free functions. + +[endsect] + +[endsect] diff --git a/doc/filesystem.qbk b/doc/filesystem.qbk new file mode 100644 index 000000000..714fe95f9 --- /dev/null +++ b/doc/filesystem.qbk @@ -0,0 +1,49 @@ +[/ + / Copyright Andrey Semashev 2024. + / + / Distributed under the Boost Software License, Version 1.0. + / (See accompanying file LICENSE_1_0.txt or copy at + / https://www.boost.org/LICENSE_1_0.txt) + /] + +[library Boost.Filesystem + [quickbook 1.7] + [authors [Dawes, Beman], [Semashev, Andrey]] + [copyright 2002-2015 Beman Dawes] + [copyright 2019-2024 Andrey Semashev] + [license + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + [@https://www.boost.org/LICENSE_1_0.txt]). + ] + [id filesystem] + [source-mode c++] + [version 4] +] + +[c++] + +[def __boost_build__ [@https://www.boost.org/doc/libs/release/tools/build/doc/html/index.html Boost.Build]] +[def __boost_system__ [@https://www.boost.org/doc/libs/release/libs/system/doc/html/system.html Boost.System]] + +[template github_issue[key][@https://github.com/boostorg/filesystem/issues/[key] #[key]]] +[template github_pr[key][@https://github.com/boostorg/filesystem/pull/[key] PR#[key]]] +[template trac_issue[key][@https://svn.boost.org/trac/boost/ticket/[key] #[key]]] + +[template super[x]''''''[x]''''''] +[template sub[x]''''''[x]''''''] + +[include intro.qbk] +[include install.qbk] +[include tutorial.qbk] +[include cautions.qbk] +[include portability_guide.qbk] +[include reference.qbk] +[include faq.qbk] +[include design.qbk] +[include v3.qbk] +[include v4.qbk] +[include deprecated.qbk] +[include issue_reporting.qbk] +[include changelog.qbk] +[include acknowledgements.qbk] diff --git a/doc/install.qbk b/doc/install.qbk new file mode 100644 index 000000000..95fb473bc --- /dev/null +++ b/doc/install.qbk @@ -0,0 +1,216 @@ +[/ + / Copyright Andrey Semashev 2024. + / + / Distributed under the Boost Software License, Version 1.0. + / (See accompanying file LICENSE_1_0.txt or copy at + / https://www.boost.org/LICENSE_1_0.txt) + /] + +[section:install Installing and using the library] + +[section:platform_requirements Supported compilers and platforms] + +The library requires a C++11 compiler as a minimum and is regularly tested with the following +compilers: + +* GCC 4.8 and newer on Linux. +* Clang 3.5 and newer with libstdc++ and libc++ on Linux. +* Apple Clang 13 on Mac OS. +* MSVC 14.0 and newer on Windows. +* Clang-cl 16.0.6 on Windows. +* MinGW-w64 with GCC 8 and newer on Windows. +* GCC 7 on Cygwin and Cygwin64. + +The library supports POSIX systems and Windows 10 and newer. Note that many operating systems +not normally thought of as POSIX systems, such as mainframe legacy operating systems or +embedded operating systems, support POSIX compatible file systems and so will work with +the Filesystem Library. + +Besides the operating systems mentioned above, the library has been used on HP-UX, IBM AIX, +SGI IRIX, OpenBSD, FreeBSD and Sun Solaris operating systems using a variety of compilers. +It is also used by several smart phone operating systems. + +[section:cygwin_notes Notes for Cygwin users] + +[@https://www.cygwin.com/ Cygwin] version 1.7 or later is required because +only versions of GCC with wide character strings are supported. + +The library's implementation code treats Cygwin as a Windows platform, and +thus uses the Windows API and uses Windows path syntax as the native path +syntax. + +[endsect] + +[endsect] + +[section:building Building the library] + +Boost.Filesystem is implemented as a separately compiled library, so you must install +binaries in a location that can be found by your linker. If you followed the +[@https://www.boost.org/doc/libs/release/more/getting_started/index.html Boost Getting Started] +instructions, that's already been done for you. + +Otherwise, the library can also be built manually using __boost_build__ or CMake using the project +files in the library directory. For example, using __boost_build__ one can build a release version +of the library with the following command line in the Boost root directory: + +[pre +b2 --with-filesystem variant=release stage +] + +With CMake, the library can be built with the following commands, also in the Boost root directory: + +[pre +mkdir build_static_release +cd build_static_release +cmake .. -DCMAKE_BUILD_TYPE=Release -DBOOST_INCLUDE_LIBRARIES=filesystem +cmake --build . +] + +The library can be built for static or dynamic (shared/dll) linking. For Boost.Build, +this is controlled with the `link` [@https://www.boost.org/doc/libs/release/tools/build/doc/html/index.html#bbv2.overview.builtins.features +property] which can have values `shared` and `static`. For example, to build shared +libraries: + +[pre +b2 --with-filesystem variant=release link=shared stage +] + +For CMake, the `BUILD_SHARED_LIBS` option enables building shared libraries. Note that +with CMake users typically have to create a separate build directory for every +build configuration. + +[pre +mkdir build_shared_release +cd build_shared_release +cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=1 -DBOOST_INCLUDE_LIBRARIES=filesystem +cmake --build . +] + +When using Boost.Filesystem as a shared library, users should define `BOOST_ALL_DYN_LINK` or +`BOOST_FILESYSTEM_DYN_LINK` macros when compiling their code. This will configure the auto-linking +process to link with the shared library instead of the static one. See the +[@https://www.boost.org/development/separate_compilation.html Separate Compilation] page for more details. + +[endsect] + +[section:config_macros Configuration Macros] + +Users may define the following macros if desired. Sensible defaults are +provided, so users can ignore these macros unless they have special needs. + +Some of the macros can be defined when compiling user's code, which will affect library interfaces. +Other macros can be defined during Boost.Filesystem compilation, which affect library implementation. +Those macros need not be defined when building code that uses Boost.Filesystem. + +[table +[[Macro Name] [Default] [Affects library usage] [Affects library build] [Effect if defined]] +[ + [`BOOST_FILESYSTEM_VERSION`] + [3] + [\u2714][] + [Selects the Boost.Filesystem library version. Can have values of 3 or 4. + Defining to 4 also implies `BOOST_FILESYSTEM_NO_DEPRECATED`.] +] +[ + [`BOOST_FILESYSTEM_NO_DEPRECATED`] + [Not defined] + [\u2714][] + [Deprecated features are excluded from headers.] +] +[ + [`BOOST_FILESYSTEM_DYN_LINK`] + [Defined if `BOOST_ALL_DYN_LINK` is defined, otherwise not defined.] + [\u2714][] + [The Boost.Filesystem library is dynamically linked. If not defined, + static linking is assumed.] +] +[ + [`BOOST_FILESYSTEM_NO_LIB`] + [Defined if `BOOST_ALL_NO_LIB` is defined, otherwise not defined.] + [\u2714][] + [Boost.Filesystem library does not use the Boost auto-link + facility.] +] +[ + [`BOOST_FILESYSTEM_DISABLE_SENDFILE`] + [Not defined. `sendfile` API presence detected at library build time.] + [][\u2714] + [Boost.Filesystem library does not use the `sendfile` system call on Linux. + The `sendfile` system call started accepting regular file descriptors as the target in Linux 2.6.33.] +] +[ + [`BOOST_FILESYSTEM_DISABLE_COPY_FILE_RANGE`] + [Not defined. `copy_file_range` API presence detected at library build time.] + [][\u2714] + [Boost.Filesystem library does not use the `copy_file_range` system call on Linux. + The `copy_file_range` system call was introduced in Linux kernel 4.5 and started operating across filesystems in 5.3.] +] +[ + [`BOOST_FILESYSTEM_DISABLE_STATX`] + [Not defined. `statx` presence detected at library build time.] + [][\u2714] + [Boost.Filesystem library does not use the `statx` system call on Linux. + The `statx` system call was introduced in Linux kernel 4.11.] +] +[ + [`BOOST_FILESYSTEM_DISABLE_GETRANDOM`] + [Not defined. `getrandom` API presence detected at library build time.] + [][\u2714] + [Boost.Filesystem library does not use the `getrandom` system call on Linux. + The `getrandom` system call was introduced in Linux kernel 3.17.] +] +[ + [`BOOST_FILESYSTEM_DISABLE_ARC4RANDOM`] + [Not defined. `arc4random` API presence detected at library build time.] + [][\u2714] + [Boost.Filesystem library does not use the `arc4random_buf` system call on BSD systems. + The `arc4random` API was introduced in OpenBSD 2.1 and FreeBSD 8.0.] +] +[ + [`BOOST_FILESYSTEM_DISABLE_BCRYPT`] + [Not defined. BCrypt API presence detected at library build time.] + [][\u2714] + [Boost.Filesystem library does not use the BCrypt API on Windows. Has no effect on other platforms.] +] +] + +User-defined `BOOST_POSIX_API` and `BOOST_WINDOWS_API` macros, which were supported +in older Boost.Filesystem versions, are no longer supported and should not be defined by users. + +In order to define macros when building Boost.Filesystem one can use `define` property with +Boost.Build or `-D` option with CMake. For example: + +[pre +b2 --with-filesystem variant=release define=BOOST_FILESYSTEM_DISABLE_STATX stage +] + +or: + +[pre +mkdir build_static_release +cd build_static_release +cmake .. -DCMAKE_BUILD_TYPE=Release -DBOOST_INCLUDE_LIBRARIES=filesystem -DBOOST_FILESYSTEM_DISABLE_STATX +cmake --build . +] + +For new code using Boost.Filesystem, defining `BOOST_FILESYSTEM_NO_DEPRECATED` before including +filesystem headers is strongly recommended. This prevents inadvertent use of old features, +particularly legacy function names, that have been replaced and are going to go away in the future. + +[endsect] + +[section:headers Headers and namespaces] + +Library components can be introduced by including one of the headers in the `boost/filesystem` +directory or `boost/filesystem.hpp`, which includes all headers in `boost/filesystem`. + +Library components are defined in the `boost::filesystem` namespace. + +Do not include headers from `boost/filesystem/detail` directory or use symbols from +the `boost::filesystem::detail` namespace. Those are implementation details of the library, +they are not part of the public interface and may be changed or removed without notice. + +[endsect] + +[endsect] diff --git a/doc/intro.qbk b/doc/intro.qbk new file mode 100644 index 000000000..e09c85a26 --- /dev/null +++ b/doc/intro.qbk @@ -0,0 +1,77 @@ +[/ + / Copyright Andrey Semashev 2024. + / + / Distributed under the Boost Software License, Version 1.0. + / (See accompanying file LICENSE_1_0.txt or copy at + / https://www.boost.org/LICENSE_1_0.txt) + /] + +[section:intro Introduction] + +The Boost.Filesystem library provides facilities to manipulate files and directories, +and the paths that identify them. + +The features of the library include: + +* A modern C++ interface, highly compatible with the C++ standard library. + + Many users say the interface is their primary motivation for using + Boost.Filesystem. They like its use of familiar idioms based on standard library + containers, iterators, and algorithms. They like having errors reported by + throwing exceptions. + +* Portability between operating systems. + * At the C++ syntax level, it is convenient to learn and use one interface + regardless of the operating system. + * At the semantic level, behavior of code is reasonably portable across + operating systems. + * Dual generic or native path format support encourages program + portability, yet still allows communication with users in system specific + formats. +* Error handling and reporting via C++ exceptions (the default) or error codes. + * C++ exceptions are the preferred error reporting mechanism for most + applications. The exception thrown includes the detailed error code + information important for diagnosing the exact cause of file system errors. + * Error reporting via error code allows user code that provides detailed + error recovery to avoid becoming so littered with try-catch blocks as to be + unmaintainable. +* Suitable for a broad spectrum of applications, ranging from simple + script-like operations to extremely complex production code. + * At the simple script-like end of the spectrum, the intent is not to + compete with Python, Perl, or shell languages, but rather to provide + filesystem operations when C++ is already the language of choice. + * Finer grained control over operations and error handling is available to + support more complex applications or other cases where throwing exceptions + isn't desired. +* Forms the basis for [@https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4100.pdf ISO/IEC TS 18822], + the C++ standard library Filesystem Technical Specification. + +[endsect] + +[section:docs Documentation] + +This documentation consists of a number of sections describing the library interface +and usage, as well as historical insight and rationale behind the current design. + +* [link filesystem.tutorial Tutorial] - A gentle introduction to the library, + with example programs provided for you to experiment with. This section + is recommended for developers new to the library. +* [link filesystem.reference Reference] - Formal documentation in the + style of the C++ standard for every component of the library. This section + is useful during active usage of the library, for detailed description + of library interfaces. +* [link filesystem.faq FAQ] - Frequently asked questions. +* [link filesystem.portability_guide Portability Guide] - Help for those + concerned with writing code to run on multiple operating systems. +* [link filesystem.deprecated Deprecated Features] - Identifies + deprecated features and their replacements. +* [link filesystem.v4 Version 4 Description] - Summary of changes from + Version 3. +* [link filesystem.v3 Version 3 Description] - Historical documents, + aimed at users of prior Boost.Filesystem versions. +* [link filesystem.v1 Original Design] - Historical document from + the start of the Version 1 design process. +* [link filesystem.do_list Do List] - Boost.Filesystem development work + in the pipeline. + +[endsect] diff --git a/doc/issue_reporting.qbk b/doc/issue_reporting.qbk new file mode 100644 index 000000000..82f12b67f --- /dev/null +++ b/doc/issue_reporting.qbk @@ -0,0 +1,194 @@ +[/ + / Copyright Andrey Semashev 2024. + / + / Distributed under the Boost Software License, Version 1.0. + / (See accompanying file LICENSE_1_0.txt or copy at + / https://www.boost.org/LICENSE_1_0.txt) + /] + +[section:issue_reporting Issue reporting] + +Boost.Filesystem issues such as bug reports or feature requests should be reported via a [@https://github.com/boostorg/filesystem/issues/new +GitHub ticket]. + +[@https://github.com/boostorg/filesystem/pulls GitHub pull requests] are encouraged, too, although anything beyond really trivial fixes needs +a ticket. + +A timely response to your bug report is much more likely if [*the problem can be immediately reproduced without guesswork and regression tests +can be easily created]. + +You need to provide the following: + +# A simple test program that: + * Illustrates the problem, and + * Automatically yields an unambiguous pass or fail result - returning zero for pass and non-zero for fail is preferred, and + * Can be used as the basis for adding tests to Boost.Filesystem's regression test suite. +# The compiler, standard library, platform, and Boost version you used to build and run your test program. +# A description of how to build and run the test program. +# A copy of the output from the test program, if any. + +See [link filesystem.issue_reporting.rationale Rationale] to find out why the above is needed. + +For a mostly automatic framework to provide the above, read on! + +[section:framework Bug reporting framework] + +The directory [^['[*boost-root]]\/libs\/filesystem\/bug] provides a bug test program ([link filesystem.issue_reporting.using_framework.bug_cpp +`bug.cpp`]) and a build file (`Jamfile.v2`). Here is what you need to do: + +# Add one or more test cases to [link filesystem.issue_reporting.using_framework.bug_cpp `bug.cpp`] using any text or program editor. +# [link filesystem.issue_reporting.using_framework.build_and_test Build and test]. +# Attach copies of the [link filesystem.issue_reporting.using_framework.test_output Test output] and test program to the + [@https://github.com/boostorg/filesystem/issues/new GitHub ticket]. + +That's it! When you complete those steps, you will be done! + +The test output supplies all of the basic information about the compiler, std library, platform, Boost version, and command line, and the test +cases you have added should make it easy for the library maintainer to reproduce the problem. + +[endsect] + +[section:using_framework Using the framework] + +[section:bug_cpp `bug.cpp`] + +Here is `bug.cpp` as supplied. To report a real bug, use `BOOST_TEST` and `BOOST_TEST_EQ` macros to build your own test cases. You can delete +the three tests already in `bug.cpp`: + +[import ../bug/bug.cpp] +[bug_cpp] + +[endsect] + +[section:build_and_test Build and test] + +[table +[[POSIX-like systems] [Microsoft Windows]] +[[ +[pre +cd \/libs\/filesystem\/bug +..\/..\/..\/b2 -a +bin\/bug +] +] +[ +[pre +cd \\libs\\filesystem\\bug +..\\..\\..\\b2 -a +bin\\bug +] +]] +] + +[endsect] + +[section:test_output Test output] + +Running the test on Windows produced this test output: + +[pre +Microsoft Visual C++ version 14.0 +Dinkumware standard library version 610 +Win32 +Boost version 1.58.0 +Command line: bin\\bug +bug.cpp(10): test '2 + 2 == 5' failed in function + 'int __cdecl test_main(int,char *\[\])' +bug.cpp(11): test '4 + 4 == 9' failed in function + 'int __cdecl test_main(int,char *\[\])': '8' != '9' +2 errors detected. +] + +The test framework runs `test_main()` from a `try` block with a `catch` block that reports exceptions via `std::exception::what()`. So the output +will differ if an exception is thrown. + +[endsect] + +[section:background_info Background information] + +You should now have enough information to file an easy-to-reproduce bug report. So you can skip reading the rest of this page unless you need +to do something a bit out of the ordinary. + +[section:b2_command_line_options `b2` command line] + +`b2` (formerly `bjam`) usage: + +[pre +b2 \[options\] \[properties\] \[target\] +] + +__boost_build__ `b2` has many options, properties, and targets, but you will not need most of them for bug reporting. Here are a few you might +find helpful: + +[table `b2` Options +[[Option] [Effect]] +[[[pre -a]] +[ +Rebuild everything rather than just out-of-date targets. Used in the example build above to ensure libraries are built with the same setup +as the test program. +]] +] + +[table `b2` Properties +[[Property] [Effect]] +[[[pre address-model=['n]] + +where ['n] is 32 or 64.] +[ +Explicitly request either 32-bit or 64-bit code generation. This typically requires that your compiler is appropriately configured. +]] +[[[pre variant=['string]] + +where ['string] is `debug` or `release`.] +[ +Request debug or release build. +]] +[[[pre toolset=['string]] + +where ['string] is composed of the compiler name and optionally, a version.] +[ +The C++ compiler to use. For example, `gcc`, `gcc-4.9`, `clang-3.3`, or `msvc-14.0`. If the version is imitted, the default compiler version +is used. +]] +[[[pre include=['string]]] +[ +Additional include paths for C and C++ compilers. +]] +[[[pre cxxflags=['string]]] +[ +Custom options to pass to the C++ compiler. +]] +[[[pre define=['string]]] +[ +Additional macro definitions for C and C++ compilers. ['string] should be either `SYMBOL` or `SYMBOL=VALUE` +]] +] + +[endsect] + +[endsect] + +[endsect] + +[section:rationale Rationale] + +Here is the request list again, with rationale added: + +# A simple test program that: + * Illustrates the problem ['\[Code communicates more clearly than prose. If it looks like it will it will take some time to figure out + exactly what the problem is, or worse yet, might result in a wild-goose chase, the bug report gets set aside to be worked on later and + then is often forgotten.\]] and + * Automatically yields an unambiguous pass or fail result - returning zero for pass and non-zero for fail is preferred ['\[Prevents + miscommunications and allows use in automatic regression tests.\]], and + * Can be used as the basis for adding tests to Boost.Filesystem's regression test suite ['\[With good test cases fixes come easier and + regressions become less likely\]]. +# The compiler, standard library, platform, and Boost version you used to build and run your test program. ['\[The implementation includes + much platform dependent code, and also depends on the other factors mentioned. Know these things upfront brings the bug report into focus + without having to ask for more information.\]] +# A description of how to build and run the test program. ['\[If `b2` (formerly known as `bjam`) is used as the build engine, this is not + a concern, but otherwise much more information is needed.\]] +# A copy of the output from the test program, if any. ['\[Avoids misinterpreting results.\]] + +[endsect] + +[endsect] diff --git a/doc/portability_guide.qbk b/doc/portability_guide.qbk new file mode 100644 index 000000000..c82d4f7ca --- /dev/null +++ b/doc/portability_guide.qbk @@ -0,0 +1,205 @@ +[/ + / Copyright Andrey Semashev 2024. + / + / Distributed under the Boost Software License, Version 1.0. + / (See accompanying file LICENSE_1_0.txt or copy at + / https://www.boost.org/LICENSE_1_0.txt) + /] + +[section:portability_guide Portability Guide] + +[section:introduction Introduction] + +Like any other C++ program which performs I/O operations, there is no guarantee that a program using Boost.Filesystem will be +portable between operating systems. Critical aspects of I/O such as how the operating system interprets paths are unspecified +by the C and C++ Standards. + +It is not possible to know if a file or directory name will be valid (and thus portable) for an unknown operating system. +There is always the possibility that an operating system could use names which are unusual (numbers less than 4096, for example) +or very limited in size (maximum of six character names, for example). In other words, portability is never absolute; it is +always relative to specific operating systems or file systems. + +It is possible, however, to know in advance if a directory or file name is likely to be valid for a particular operating system. +It is also possible to construct names which are likely to be portable to a large number of modern and legacy operating systems. + +Almost all modern operating systems support multiple file systems. At the minimum, they support a native file system plus +a CD-ROM file system (Generally ISO-9669, often with Joliet extensions). + +Each file system may have its own naming rules. For example, modern versions of Windows support NTFS, FAT, FAT32, and ISO-9660 +file systems, among others, and the naming rules for those file systems differ. Each file system may also have differing rules +for overall path validity, such as a maximum length or number of sub-directories. Some legacy systems have different rules for +directory names versus regular file names. + +As a result, Boost.Filesystem's name checking functions cannot guarantee directory and file name portability. Rather, they are +intended to give the programmer a "fighting chance" to achieve portability by early detection of common naming problems. + +[endsect] + +[section:name_check_functions Name checking functions] + +A name checking function returns `true` if its argument is valid as a directory and regular file name for a particular operating +or file system. A number of these functions are provided. + +The [link filesystem.portability_guide.name_check_functions.portable_name `portable_name`] function is of particular interest +because it has been carefully designed to provide wide portability yet not overly restrict expressiveness. + +[table Library Supplied Name Checking Functions +[[Function] [Description]] +[[[#filesystem.portability_guide.name_check_functions.portable_posix_name]`bool portable_posix_name(const std::string& name)`] +[ +[*Returns:] `true` if `!name.empty()` and `name` contains only the characters specified in ['Portable Filename Character Set] +rules as defined in by POSIX ([@https://pubs.opengroup.org/onlinepubs/007904975/basedefs/xbd_chap03.html +www.opengroup.org/onlinepubs/007904975/basedefs/xbd_chap03.html]). + +The allowed characters are "0-9", "a-z", "A-Z", ".", "_", and "-". + +[*Use:] applications which must be portable to any POSIX system. +]] +[[[#filesystem.portability_guide.name_check_functions.windows_name]`bool windows_name(const std::string& name)`] +[ +[*Returns:] `true` if + +* `!name.empty()`, and +* `name` contains only the characters specified by the Windows platform SDK as valid regardless of the file system, and +* `name` is "." or ".." or does not end with a trailing space or period. + +The allowed characters are anything except `0x0-0x1F`, "<", ">", ":", """, "/", "\\", and "|". + +[*Use:] applications which must be portable to Windows. + +[note Reserved device names are not valid as file names, but are not being detected because they are still valid as a path. +Specifically, "CON", "PRN", "AUX", "CLOCK$", "NUL", "COM\[1-9\]", "LPT\[1-9\]", and these names followed by an extension +(for example, "NUL.tx7").] +]] +[[[#filesystem.portability_guide.name_check_functions.portable_name]`bool portable_name(const std::string& name)`] +[ +[*Returns:] `true` if + +* `windows_name(name)`, and +* `portable_posix_name(name)`, and +* `name` is "." or "..", or the first character of `name` is not a period or hyphen. + +[*Use:] applications which must be portable to a wide variety of modern operating systems, large and small, and to some +legacy OSs. The first character not a period or hyphen restriction is a requirement of several older operating systems. +]] +[[[#filesystem.portability_guide.name_check_functions.portable_directory_name]`bool portable_directory_name(const std::string& name)`] +[ +[*Returns:] `true` if `portable_name(name)` and `name` is "." or ".." or contains no periods. + +[*Use:] applications which must be portable to a wide variety of platforms, including OpenVMS. +]] +[[[#filesystem.portability_guide.name_check_functions.portable_file_name]`bool portable_file_name(const std::string& name)`] +[ +[*Returns:] `true` if + +* `portable_name(name)`, and +* any period is followed by one to three additional non-period characters. + +[*Use:] applications which must be portable to a wide variety of platforms, including OpenVMS and other systems which have +a concept of "file extension" but limit its length. +]] +[[[#filesystem.portability_guide.name_check_functions.native]`bool native(const std::string& name)`] +[ +[*Returns:] Implementation defined. Returns `true` for names considered valid by the operating system's native file systems. + +[*Note:] May return `true` for some names not considered valid by the operating system under all conditions (particularly +on operating systems which support multiple file systems.) +]] +] + +[endsect] + +[section:recommendations File and directory name recommendations] + +[table +[[Recommendation] [Rationale]] +[[ +Limit file and directory names to the characters "A-Z", "a-z", "0-9", period, hyphen, and underscore. + +Use any of the `portable_` [link filesystem.portability_guide.name_check_functions name checking functions] to enforce this +recommendation. +] +[ +These are the characters specified by the POSIX standard for portable directory and file names, and are also valid for Windows, +Mac OS, and many other modern file systems. +]] +[[ +Do not use a period or hyphen as the first character of a name. Do not use period as the last character of a name. + +Use [link filesystem.portability_guide.name_check_functions.portable_name `portable_name`], +[link filesystem.portability_guide.name_check_functions.portable_directory_name `portable_directory_name`], or +[link filesystem.portability_guide.name_check_functions.portable_file_name `portable_file_name`] to enforce this +recommendation. +] +[ +Some operating systems treat have special rules for the first character of names. POSIX, for example. Windows does not permit +period as the last character. +]] +[[ +Do not use periods in directory names. + +Use [link filesystem.portability_guide.name_check_functions.portable_directory_name `portable_directory_name`] to enforce +this recommendation. +] +[ +Requirement for ISO-9660 without Juliet extensions, OpenVMS filesystem, and other legacy systems. +]] +[[ +Do not use more that one period in a file name, and limit the portion after the period to three characters. + +Use [link filesystem.portability_guide.name_check_functions.portable_file_name `portable_file_name`] to enforce this +recommendation. +] +[ +Requirement for ISO-9660 level 1, OpenVMS filesystem, and other legacy systems. +]] +[[ +Do not assume names are case sensitive. For example, do not expected a directory to be able to hold separate elements named +"Foo" and "foo". +] +[ +Some file systems are case insensitive. For example, Windows NTFS is case preserving in the way it stores names, but case +insensitive in searching for names (unless running under the POSIX sub-system, it which case it does case sensitive searches). +]] +[[ +Do not assume names are case insensitive. For example, do not expect a file created with the name of "Foo" to be opened +successfully with the name of "foo". +] +[ +Some file systems are case sensitive. This is typically the case on POSIX systems. Even on Windows, NTFS supports creating +files with names in [@https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions POSIX convention], +which makes them case sensitive. +]] +[[ +Don't use hyphens in names. +] +[ +ISO-9660 level 1, and possibly some legacy systems, do not permit hyphens. +]] +[[ +Limit the length of the string returned by `path::string()` to 255 characters. Note that ISO 9660 has an explicit directory +tree depth limit of 8, although this depth limit is removed by the Juliet extensions. +] +[ +Some operating systems place limits on the total path length. For example, Windows 2000 limits paths to 260 characters total +length. +]] +[[ +Limit the length of any one name in a path. Pick the specific limit according to the operating systems and/or file systems +you wish to maintain portability to: + +* Not a concern: POSIX, Windows, MAC OS X. +* 31 characters: Classic Mac OS +* 8 characters + period + 3 characters: ISO 9660 level 1 +* 32 characters: ISO 9660 level 2 and 3 +* 128 characters (64 if Unicode): ISO 9660 with Juliet extensions +] +[ +Limiting name length can markedly reduce the expressiveness of file names, yet placing only very high limits on lengths inhibits +widest portability. +]] +] + +[endsect] + +[endsect] diff --git a/doc/reference-full.qbk b/doc/reference-full.qbk new file mode 100644 index 000000000..ee75a54f6 --- /dev/null +++ b/doc/reference-full.qbk @@ -0,0 +1,9030 @@ +[/ + / Copyright Andrey Semashev 2024. + / + / Distributed under the Boost Software License, Version 1.0. + / (See accompanying file LICENSE_1_0.txt or copy at + / http://www.boost.org/LICENSE_1_0.txt) + /] + +[template super[x]''''''[x]''''''] +[template sub[x]''''''[x]''''''] + +[h1 Filesystem Reference] + + + + + + +[table + +[ + [ +[@../../../index.htm +[$../../../boost.png]]] + [ + Filesystem Library + + Version 4] + ] + +] + + + +[table + +[ + [[@index.htm Home]    + [@tutorial.html Tutorial]    + [@reference.html Reference]    + [@faq.htm FAQ]    + [@release_history.html Releases]    + [@portability_guide.htm Portability]    + [@v4.html V4]    + [@v3.html V3 Intro]    + [@v3_design.html V3 Design]    + [@deprecated.html Deprecated]    + [@issue_reporting.html Bug Reports ]   + ] + ] + +] + + + +[h1 Reference Documentation] + + + + + +[h2 [#TOC]Table of Contents] + + + +[table + +[ + [ + + +[@#Introduction Introduction] + + [@#Definitions Definitions] + + [@#Conformance Conformance] + + [@#Header-filesystem-synopsis + Header `` synopsis] + + [@#Error-reporting Error reporting] + + [@#class-path Class `path`] + +    [@#path-Conversions `path` conversions] + +    [@#path-Conversions-to-native-format `path` + conversions to native format] + +    [@#path-Conversions-to-generic-format `path` + conversions to generic format] + +    [@#path-Encoding-conversions `path` + encoding conversions] + +    [@#path-Requirements `path` requirements] + +     [@#path-constructors `path` constructors] + +    [@#path-assignments `path` assignments] + +     [@#path-appends `path` appends] + +     [@#path-concatenation `path` concatenation] + +    [@#path-modifiers `path` modifiers] + +    [@#path-native-format-observers `path` native + format observers] + +    [@#path-generic-format-observers `path` generic + format observers] + +    [@#path-compare `path` compare] + +    [@#path-decomposition `path` decomposition] + +    [@#path-query `path` query] + +    [@#path-iterators `path` iterators] + + +    [@#path-deprecated-functions `path` deprecated functions] + +    [@#path-non-member-functions `path` non-member functions] + +    [@#path-inserter-extractor `path` inserters and extractors] + +  [@#Class-filesystem_error Class `filesystem_error`] + +    [@#filesystem_error-members `filesystem_error` + constructors] + +    [@#filesystem_error-path1 `filesystem_error` path1] + +    [@#filesystem_error-path2 `filesystem_error` path2] + +    [@#filesystem_error-what `filesystem_error` what] + +] + [ + + + + [@#Enum-file_type Enum `file_type`] + + [@#Enum-perms Enum `perms`] + + [@#file_status Class + `file_status`] + +    + [@#file_status + `file_status`][@#file_status-constructors constructors] + +    `[@#file_status-modifiers file_status-modifiers]`[@#directory_entry-observers observers] + +    `[@#file_status-observers file_status-observers]`[@#directory_entry-modifiers modifiers] + +[@#Class-directory_entry Class `directory_entry`] + +    +[@#directory_entry-constructors `directory_entry` constructors] + +    [@#directory_entry-observers `directory_entry` observers] + +    [@#directory_entry-modifiers `directory_entry` modifiers] + +[@#Class-directory_iterator Class `directory_iterator`] + +    [@#directory_iterator-members `directory_iterator` + members] + +[@#Class-recursive_directory_iterator Class `recursive_directory_iterator`] + + [@#Operational-functions + Operational functions] + + `     [@#absolute absolute] + +     [@#canonical canonical] + +     [@#copy copy] + +     [@#copy_directory copy_directory] + +     [@#copy_file copy_file] + +     [@#copy_symlink copy_symlink] + +     [@#create_directories create_directories] + +     [@#create_directory create_directory] + +     [@#create_hard_link create_hard_link] + +     [@#create_symlink create_symlink] + +     [@#creation_time creation_time] + +     [@#current_path current_path] + +     [@#exists exists] + +     [@#equivalent equivalent] + +     [@#file_size file_size] + +     [@#hard_link_count hard_link_count]` + +] + [ + + + + ` +     [@#initial_path initial_path] + +     [@#is_block_file is_block_file] + +     [@#is_character_file is_character_file] + +     [@#is_directory is_directory] + +     [@#is_empty is_empty] + +     [@#is_fifo is_fifo] + +     [@#is_other is_other] + +     [@#is_regular_file is_regular_file] + +     [@#is_reparse_file is_reparse_file] + +     [@#is_socket is_socket] + +     [@#is_symlink is_symlink] + +     [@#last_write_time last_write_time] + +     [@#permissions permissions] + +     [@#read_symlink read_symlink] + +     [@#relative relative] + +     [@#remove remove] + +     [@#remove_all remove_all] + +     [@#rename rename] + +     [@#resize_file resize_file] + +     [@#space space] + +     [@#status status] + +     [@#status_known status_known] + +     [@#symlink_status symlink_status] + +     [@#system_complete system_complete] + +     [@#temp_directory_path temp_directory_path] + +     [@#unique_path unique_path] + +     [@#weakly_canonical weakly_canonical] +` + [@#File-streams File streams] + +[@#path-decomposition-table Path decomposition table] + + [@#windows-path-prefixes Long paths on Windows and the + [*\\\\?\\] namespace prefix] + +[@#Acknowledgements Acknowledgements] + +[@#References References] + +  + +] + ] + +] + + + + +[h2 [#Introduction]Introduction] + + + + +This reference documentation describes components that C++ programs may use +to perform operations involving file systems, including paths, regular files, +and directories. + + + + +[h2 [#Conformance]Conformance \[fs.conformance\]] + + + +[h3 ISO/IEC 9945 conformance \[fs.conform.9945\]] + + + +Some behavior in this reference documentation is specified by reference to ISO/IEC 9945. How such behavior is actually implemented is unspecified. + + +[: + + +\[['Note:] This constitutes an "as if" rule for implementation of +operating system dependent behavior. In practice implementations will usually call native +operating system API's. ['—end note]\] + + +] + + + + +Implementations are encouraged to provide such behavior + +as it is defined by ISO/IEC 9945. Implementations shall document any +behavior that differs from the behavior defined by ISO/IEC 9945. Implementations that do not support exact +ISO/IEC 9945 behavior are +encouraged to provide behavior as close to ISO/IEC 9945 behavior as is reasonable given the +limitations of actual operating systems and file systems. If an implementation cannot provide any +reasonable behavior, the implementation shall report an error in an +implementation-defined manner. + + +[: + + +\[['Note:] Such errors might be reported by an `#error` directive, a ` +static_assert`, a `filesystem_error` exception, a special +return value, or some other manner. ['—end note]\] + + +] + + + + +Implementations are not required to provide behavior that is not supported by +a particular file system. + + +[: + + +\[['Example:] The [@http://en.wikipedia.org/wiki/FAT_filesystem +FAT file system] used by some memory cards, camera memory, and floppy discs +does not support hard links, symlinks, and many other features of more capable +file systems. Implementations are only required to support the FAT features +supported by the host operating system. ['—end example]\] + + +] + + + + +The behavior of functions described in this +reference +may differ from their specification in +the presence of [@#file-system-race file system races]. No diagnostic is required. + + + + +If the possibility of a file system race would make it unreliable for a program to +test for a precondition before calling a function described in this reference documentation, [' +Requires] is not specified for the condition. Instead, the condition is +specified as a ['Throws] condition. + + +[: + + +\[['Note:] As a design practice, preconditions are not specified when it +is unreasonable for a program to detect them prior to calling the function. [' +—end note]\] + + +] + + + +[h3 Operating system dependent conformance \[fs.conform.os\]] + + + +Some behavior is specified in this reference documentation as being +operating system dependent (\[fs.def.osdep\]). The operation system an +implementation is dependent upon is implementation defined. + + + + +It is permissible for an implementation to be dependent upon an operating +system emulator rather than the actual operating system. + + +[: + + +\[['Example:] An implementation uses Cygwin, a Linux® API emulator for +some Windows® operating system versions. The implementation would define Cygwin +as its operating system. Users could refer to the Cygwin documentation to find +details of the operating system dependent behavior.  ['—end example]\] + + + + +['It is user and conformance test +detectable that such an implementation is running on Cygwin. Users would be +misled and conformance tests would fail if the implementation defined Linux or +Windows rather than Cygwin as the operating system, since real behavior is a +blend of the two.] + + +] + + + +[h2 [#Definitions]Definitions \[fs.definitions\]] + + + +The following definitions shall apply throughout this reference documentation: + + + +[h3 [#operatingsystemdependent]operating system dependent behavior +\[fs.def.osdep\]] + + + +Behavior that is dependent upon the behavior +and characteristics of an operating system. See \[fs.conform.os\]. + + + +[h3 [#file]file \[fs.def.file\]] + + + +An object that can be written to, or read from, or both. A file +has certain attributes, including type. File types include regular files +and directories. Other types of files, such as symbolic links, may be supported by the +implementation. + + + +[h3 [#file-system]file system \[fs.def.filesystem\]] + + + +A collection of files and certain of their attributes. + + + +[h3 [#filename]filename \[fs.def.filename\]] + + + +The name of a file. Filenames ` + "."`  +and `".."`  have special meaning. The follow characteristics of + filenames are operating system dependent: + + + + * + + +The permitted characters. See \[[@#Operating-system-examples fs.os.examples]\]. + + + + * + + +Specific filenames that are not permitted. + + + + * + + +Additional filenames that have special meaning. + + + + * + + +Case awareness and sensitivity during path resolution. + + + + * + + +Special rules that may apply to file types other than regular + files, such as directories. + + + + + +[h3 [#path]path \[fs.def.path\]] + + + +A sequence of elements that identify +the location of a file within a filesystem. The elements are the ['root-name[sub opt]], [' +root-directory[sub opt]], and an optional sequence of filenames. \[['Note:] +A [@#pathname pathname] is the concrete representation of a path. ['—end note]\] + + + + +[h3 [#Absolute-path]absolute path \[fs.def.absolute-path\]] + + + +A path that +unambiguously +identifies the location of a file without reference to an additional starting +location. The elements of a path that determine if it is absolute are +operating system dependent. + + + + +[h3 [#Relative-path]relative path \[fs.def.relative-path\]] + + + +A path that +is not absolute, and so only +unambiguously +identifies the location of a file when resolved relative to +an implied starting location. The elements of a path that determine if it is +relative are operating system dependent.  \[['Note:] +Paths `"."` and `".."` are relative paths. ['—end note]\] + + + +[h3 [#canonical-path]canonical path \[fs.def.canonical-path\]] + + + +An absolute path that has +no elements that are symbolic links, and no `"."` or `".."` elements. + + + +[h3 [#pathname]pathname \[fs.def.pathname\]] + + + +A character string that represents +the name of a +path. Pathnames are formatted according to the generic pathname grammar or an +operating system dependent +native pathname format. + + + + +[h3 [#native-pathname-format]native pathname format \[fs.def.native\]] + + + +The operating system dependent pathname format accepted by the host operating system. + + + +[h3 [#normal-form]normal form path \[fs.def.normal\]] + + + +A path with no redundant directory separators, current directory (['dot]) or parent directory (['dot-dot]) +elements. The normal form for an empty path is an empty path. \[[*v3:] The normal form +for a path ending in a ['directory-separator] that is not the root directory +is the same path with a current directory (['dot]) element appended.\] + + + +[h3 [#link]link \[fs.def.link\]] + + + +A directory entry object that associates a +filename with a file. On some file systems, several directory entries can +associate names with the same file. + + + +[h3 [#hard-link]hard link \[fs.def.hardlink\]] + + + +A link to an existing file. Some +file systems support multiple hard links to a file. If the last hard link to a +file is removed, the file itself is removed. + + +[: + + +\[['Note:] A hard link can be thought of as a shared-ownership smart +pointer to a file.[' —end note]\] + + +] + + + +[h3 [#symbolic-link]symbolic link \[fs.def.symlink\]] + + + +A type of file with the +property that when the file is encountered during pathname resolution, a string +stored by the file is used to modify the pathname resolution. + + +[: + + +\[['Note:] A symbolic link can be thought of as a raw pointer to a file. +If the file pointed to does not exist, the symbolic link is said to be a +"dangling" symbolic link.[' —end note]\] + + +] + + + +[h3 [#file-system-race]file system race \[fs.def.race\]] + + + +The condition that occurs +when multiple threads, processes, or computers interleave access and +modification of +the same object within a file system. + + + +[h2 [#generic-pathname-format]Generic pathname format \[path.generic\]] + + + +['pathname: + +            root-name[sub opt] +root-directory[sub opt] relative-path[sub opt]] + + + + +['root-name: + +            ]An +operating system dependent name that identifies the starting location for +absolute paths. + + +[: + [: + + +\[['Note:] Many operating systems define a name +beginning with two ['directory-separator] characters as a ['root-name] +that identifies network or other resource locations. Some operating systems define a single letter followed by a colon as a drive +specifier - a ['root-name] identifying a specific device such as a disc drive. ['—end note]\] + + + ] + + +] + + + + +['root-directory: + +            +directory-separator] + + + + +['relative-path: + +            +filename + +            relative-path +directory-separator + +            relative-path +directory-separator filename] + + + + +['filename: + +            name + +            ]`"."`[' + +            ]` +".."` + + + + +['preferred-separator: + +            ]An +operating system dependent directory separator character. May be a synonym for [' `"/"`.] + + + + +['directory-separator: + +            `"/" + +      "/"` directory-separator + +            +preferred-separator + +            +preferred-separator directory-separator] + + + + +Multiple successive ['directory-separator] characters are considered to +be the same as one ['directory-separator] character. + + + + +The ['filename] +`"."` is considered to be a reference to the current directory. The +['filename] `".."` is considered to be a reference to the +parent +directory. Specific ['filenames] may have special meanings for a particular +operating system. + + + +[h2 [#Operating-system-examples]Operating system dependent examples (Informative) \[fs.os.examples\]] + + + +Certain features are specified in this reference documentation as being operating system dependent. The following table shows the application of those +specifications for operating systems that use the ISO/IEC 9945 or Windows® application program interfaces +(APIs).[super \[footnote1\]] + + + +[table + +[ + [ + + +[*Feature] + +] + [ + + +[*Section] + +] + [ + + +[*ISO/IEC 9945 + + POSIX]®[* API] + +] + [ + + +[*Windows]®[* API] + +] + [ + + +[*Notes] + +] + ] + + +[ + [ + + +`path + + ::value_type` + +] + [ + + +\[[@#class-path class.path]\] + +] + [ + + +`char` + +] + [ + + +`wchar_t` + +] + [ + + +  + +] + ] + + +[ + [ + + +`path::preferred + + _separator` + +] + [ + + +\[[@#class-path class.path]\] + +] + [ + + +`'/'` + +] + [ + + +`L'\\\\'` (single backslash) + +] + [ + + +  + +] + ] + + +[ + [ + + +`path("/") + + .is_absolute() + + path("c:/") + + .is_absolute()` + +] + [ + + +\[[@#path-query path] + + [@#path-query .query]\] + +] + [ + + +` + + true + + + + false` + +] + [ + + +` + + false + + + + true` + +] + [ + + +  + +] + ] + + +[ + [ + + +`path` argument disambiguation between generic format and + native format + +] + [ + + +\[[@#path-Conversions-to-native-format path.arg] + + [@#path-Conversions-to-native-format .fmt.cvt]\] + +] + [ + + +Not required + +] + [ + + +Not required + +] + [ + + +There is no need to distinguish between the generic format and native + format for these operating systems. + +] + ] + + +[ + [ + + +`path` argument format conversion + +] + [ + + +\[[@#path-Conversions-to-native-format path.arg] + + [@#path-Conversions-to-native-format .fmt.cvt]\] + +] + [ + + +No conversion performed + +] + [ + + +No conversion performed + +] + [ + + +The generic format is already acceptable to the native API of these operating systems. + +] + ] + + +[ + [ + + +`path + + ("/cats/jane") + + .c_str() + + path| + + ("/cats/jane/") + + .c_str()` + +] + [ + + +\[[@#path-Conversions-to-native-format path.arg] + + [@#path-Conversions-to-native-format .fmt.cvt]\] + +] + [ + + +` + + + + "/cats/jane" + + + + + + "/cats/jane/"` + +] + [ + + +` + + + + L"/cats/jane" + + + + + + L"/cats/jane/"` + +] + [ + + +These operating systems accept the same native separator between + directory names and a final file name, so no format conversion is performed. + Other operating systems might require conversion. + +] + ] + + +[ + [ + + +Format conversion by `path` native format observers + +] + [ + + +\[[@#path-native-format-observers path.native] + + [@#path-native-format-observers .obs]\] + +] + [ + + +No conversion performed + +] + [ + + +No conversion performed + +] + [ + + +For efficiency, `path` objects are required to store pathnames in the native + format regardless of operating system. + +] + ] + + +[ + [ + + +Format conversion by `path` generic format observers + +] + [ + + +\[[@#path-generic-format-observers path] + + [@#path-generic-format-observers .generic] + + [@#path-generic-format-observers .obs]\] + +] + [ + + +No conversion performed + +] + [ + + +Backslashes converted to slashes + +] + [ + + +  + +] + ] + + +[ + [ + + +`p. + + make_preferred()` + +] + [ + + +\[[@#path-modifiers fs.path] + + [@#path-modifiers .modifiers]\] + +] + [ + + +No change + +] + [ + + +Slashes converted to backslashes + +] + [ + + +  + +] + ] + + +[ + [ + + +Characters prohibited in filenames + +] + [ + + +\[[@#filename fs.def] + + [@#filename .filename]\] + +] + [ + + +0x00, `'/'` + +] + [ + + +0x00-0x1F, `'"'`, `'*'`,` '*'`, + `'<'`, + `'>'`, `'?'`, `'\\\\'` (single backslash), + `'/'`, `'|'` + +] + [ + + +Many operating systems prohibit the ASCII control characters (0x00-0x1F) + in filenames. + +] + ] + + +[ + [ + + +Initial imbued `path` locale + +] + [ + + +\[[@#path-imbued-locale path] + + [@#path-imbued-locale .imbued] + + [@#path-imbued-locale .locale]\] + +] + [ + + +`std:: + +  locale("") + + `[super \[footnote 2\]] + +] + [ + + +Implementation supplied locale using `MultiByte + +  ToWideChar` + and `WideChar + +  ToMultiByte` with a codepage of `CP_ACP` + if `AreFileApisANSI` is true, otherwise codepage `CP_OEMCP`.[super \[footnote + 3\]] + +] + [ + + +Apple OS X®:  Implementation supplied locale providing UTF-8 `codecvt` + facet.[super \[footnote 4\]] + +] + ] + +] + + + +[super \[footnote1\]] OS X® and Windows® are examples of commercially +available operating systems. This information is given for the convenience of +users of this document and does not constitute an endorsement by ISO or IEC of +these products. + + + + +[super \[footnote 2\] ]Rationale: ISO C specifies `std::locale("")` as "the locale-specific native +environment", while ISO/IEC 9945 says it "Specifies an implementation-defined native +environment." + + + + +[super \[footnote 3\] ]Rationale: This is the current behavior of C and C++ +standard library functions that perform file operations using narrow character +strings to identify paths. Changing this behavior would be surprising and at +variance with existing code, particularly where user input is involved. + + + + +[super \[footnote 4\]] Rationale: Vendor's documentation states "All BSD +system functions expect their string parameters to be in UTF-8 encoding and +nothing else." + + + +[h2 [#Header-filesystem-synopsis]Header `` synopsis +\[filesystem.synopsis\]] + + + + + +``` +namespace boost +{ + namespace filesystem + { + class [@#class-path path]; + + bool lexicographical_compare(path::iterator first1, path::iterator last1, + path::iterator first2, path::iterator last2); + void swap(path& lhs, path& rhs) noexcept; + std::size_t [@#hash_value hash_value](const path& p); + + bool operator==(const path& lhs, const path& rhs); + bool operator!=(const path& lhs, const path& rhs); + bool operator< (const path& lhs, const path& rhs); + bool operator<=(const path& lhs, const path& rhs); + bool operator> (const path& lhs, const path& rhs); + bool operator>=(const path& lhs, const path& rhs); + + path operator/ (const path& lhs, const path& rhs); + + std::ostream& operator<<( std::ostream& os, const path& p ); + std::wostream& operator<<( std::wostream& os, const path& p ); + std::istream& operator>>( std::istream& is, path& p ); + std::wistream& operator>>( std::wistream& is, path& p ) + + class [@#Class-filesystem_error filesystem_error]; + class [@#Class-directory_entry directory_entry]; + + class [@#Class-directory_iterator directory_iterator]; + + // enable c++11 range-based for statements + const directory_iterator& [@#directory_iterator-non-member-functions begin](const directory_iterator& iter); + directory_iterator [@#directory_iterator-non-member-functions end](const directory_iterator&); + + + // enable BOOST_FOREACH + directory_iterator& range_begin(directory_iterator& iter); + directory_iterator range_begin(const directory_iterator& iter); + directory_iterator range_end(const directory_iterator&); + + class [@#Class-recursive_directory_iterator recursive_directory_iterator]; + + // enable c++11 range-based for statements + const recursive_directory_iterator& + [@#recursive_directory_iterator-non-member-functions begin](const recursive_directory_iterator& iter); + recursive_directory_iterator + [@#recursive_directory_iterator-non-member-functions end](const recursive_directory_iterator&); + + + // enable BOOST_FOREACH + recursive_directory_iterator& + range_begin(recursive_directory_iterator& iter); + recursive_directory_iterator + range_begin(const recursive_directory_iterator& iter); + recursive_directory_iterator + range_end(const recursive_directory_iterator&); + + enum [#file_type]file_type + { + status_error, file_not_found, regular_file, directory_file, + symlink_file, block_file, character_file, fifo_file, socket_file, + reparse_file, type_unknown + }; + + enum [@#Enum-perms perms] + { + no_perms, + owner_read, owner_write, owner_exe, owner_all, + group_read, group_write, group_exe, group_all, + others_read, others_write, others_exe, others_all, all_all, + set_uid_on_exe, set_gid_on_exe, sticky_bit, + perms_mask, perms_not_known, + add_perms, remove_perms, symlink_perms + }; + + class [@#file_status file_status]; + + struct [#space_info]space_info // returned by [@#space space] function + { + uintmax_t capacity; + uintmax_t free; + uintmax_t available; // free space available to non-privileged process + }; + + enum class [#copy_options]copy_options + { + none = 0u, + // [@#copy_file copy_file] options + skip_existing, + overwrite_existing, + update_existing, + synchronize_data, + synchronize, + ignore_attribute_errors, + // [@#copy copy] options + recursive, + copy_symlinks, + skip_symlinks, + directories_only, + create_symlinks, + create_hard_links + }; + + enum class [#directory_options]directory_options + { + none = 0u, + skip_permission_denied, + follow_directory_symlink, + pop_on_error + }; + + // [@#Operational-functions operational functions] + + path [@#absolute absolute](const path& p, const path& base=current_path()); + path [@#absolute absolute](const path& p, system::error_code& ec); + path [@#absolute absolute](const path& p, const path& base, + system::error_code& ec); + + path [@#canonical canonical](const path& p, const path& base = current_path()); + path [@#canonical canonical](const path& p, system::error_code& ec); + path [@#canonical canonical](const path& p, const path& base, + system::error_code& ec); + + void [@#copy copy](const path& from, const path& to); + void [@#copy copy](const path& from, const path& to, + system::error_code& ec); + void [@#copy copy](const path& from, const path& to, + [@#copy_options copy_options] options); + void [@#copy copy](const path& from, const path& to, + [@#copy_options copy_options] options, system::error_code& ec); + + bool [@#copy_file copy_file](const path& from, const path& to); + bool [@#copy_file copy_file](const path& from, const path& to, + system::error_code& ec); + bool [@#copy_file copy_file](const path& from, const path& to, + [@#copy_options copy_options] options); + bool [@#copy_file copy_file](const path& from, const path& to, + [@#copy_options copy_options] options, system::error_code& ec); + + void [@#copy_symlink copy_symlink](const path& existing_symlink, + const path& new_symlink); + void [@#copy_symlink copy_symlink](const path& existing_symlink, + const path& new_symlink, system::error_code& ec); + + bool [@#create_directories create_directories](const path& p); + bool [@#create_directories create_directories](const path& p, + system::error_code& ec); + + bool [@#create_directory create_directory](const path& p); + bool [@#create_directory create_directory](const path& p, system::error_code& ec); + bool [@#create_directory create_directory](const path& p, const path& existing); + bool [@#create_directory create_directory](const path& p, const path& existing, system::error_code& ec); + + void [@#create_directory_symlink create_directory_symlink](const path& to, + const path& new_symlink); + void [@#create_directory_symlink create_directory_symlink](const path& to, + const path& new_symlink, system::error_code& ec); + + void [@#create_hard_link create_hard_link](const path& to, const path& new_hard_link); + void [@#create_hard_link create_hard_link](const path& to, const path& new_hard_link, + system::error_code& ec); + + void [@#create_symlink create_symlink](const path& to, const path& new_symlink); + void [@#create_symlink create_symlink](const path& to, const path& new_symlink, + system::error_code& ec); + + std::time_t [@#creation_time creation_time](const path& p); + std::time_t [@#creation_time creation_time](const path& p, system::error_code& ec); + + path [@#current_path current_path](); + path [@#current_path current_path](system::error_code& ec); + void [@#current_path current_path](const path& p); + void [@#current_path current_path](const path& p, system::error_code& ec); + + bool [@#exists exists](file_status s) noexcept; + bool [@#exists exists](const path& p); + bool [@#exists exists](const path& p, system::error_code& ec) noexcept; + + bool [@#equivalent equivalent](const path& p1, const path& p2); + bool [@#equivalent equivalent](const path& p1, const path& p2, + system::error_code& ec); + + uintmax_t [@#file_size file_size](const path& p); + uintmax_t [@#file_size file_size](const path& p, system::error_code& ec); + + uintmax_t [@#hard_link_count hard_link_count](const path& p); + uintmax_t [@#hard_link_count hard_link_count](const path& p, system::error_code& ec); + + const path& [@#initial_path initial_path](); + const path& [@#initial_path initial_path](system::error_code& ec); + + bool [@#is_block_file is_block_file](file_status s) noexcept; + bool [@#is_block_file2 is_block_file](const path& p); + bool [@#is_block_file2 is_block_file](const path& p, + system::error_code& ec) noexcept; + + bool [@#is_character_file is_character_file](file_status s) noexcept; + bool [@#is_character_file2 is_character_file](const path& p); + bool [@#is_character_file2 is_character_file](const path& p, + system::error_code& ec) noexcept; + + bool [@#is_directory is_directory](file_status s) noexcept; + bool [@#is_directory2 is_directory](const path& p); + bool [@#is_directory2 is_directory](const path& p, + system::error_code& ec) noexcept; + + bool [@#is_empty is_empty](const path& p); + bool [@#is_empty is_empty](const path& p, system::error_code& ec); + + bool [@#is_fifo is_fifo](file_status s) noexcept; + bool [@#is_fifo2 is_fifo](const path& p); + bool [@#is_fifo2 is_fifo](const path& p, + system::error_code& ec) noexcept; + + bool [@#is_other is_other](file_status s) noexcept; + bool [@#is_other2 is_other](const path& p,); + bool [@#is_other2 is_other](const path& p, system::error_code& ec) noexcept; + + bool [@#is_regular_file is_regular_file](file_status s) noexcept; + bool [@#is_regular_file2 is_regular_file](const path& p); + bool [@#is_regular_file2 is_regular_file](const path& p, + system::error_code& ec) noexcept; + + bool [@#is_reparse_file is_reparse_file](file_status s) noexcept; + bool [@#is_reparse_file2 is_reparse_file](const path& p); + bool [@#is_reparse_file2 is_reparse_file](const path& p, + system::error_code& ec) noexcept; + + bool [@#is_socket is_socket](file_status s) noexcept; + bool [@#is_socket2 is_socket](const path& p); + bool [@#is_socket2 is_socket](const path& p, + system::error_code& ec) noexcept; + + bool [@#is_symlink is_symlink](file_status s noexcept); + bool [@#is_symlink2 is_symlink](const path& p); + bool [@#is_symlink2 is_symlink](const path& p, system::error_code& ec) noexcept; + + std::time_t [@#last_write_time last_write_time](const path& p); + std::time_t [@#last_write_time last_write_time](const path& p, system::error_code& ec); + void [@#last_write_time2 last_write_time](const path& p, const std::time_t new_time); + void [@#last_write_time2 last_write_time](const path& p, const std::time_t new_time, + system::error_code& ec); + + path [@#read_symlink read_symlink](const path& p); + path [@#read_symlink read_symlink](const path& p, system::error_code& ec); + + path [@#relative relative](const path& p, system::error_code& ec); + path [@#relative relative](const path& p, const path& base=current_path()); + path [@#relative relative](const path& p, + const path& base, system::error_code& ec); + + bool [@#remove remove](const path& p); + bool [@#remove remove](const path& p, system::error_code& ec); + + uintmax_t [@#remove_all remove_all](const path& p); + uintmax_t [@#remove_all remove_all](const path& p, system::error_code& ec); + + void [@#rename rename](const path& from, const path& to); + void [@#rename rename](const path& from, const path& to, + system::error_code& ec); + + void [@#resize_file resize_file](const path& p, uintmax_t size); + void [@#resize_file2 resize_file](const path& p, uintmax_t size, + system::error_code& ec); + + [@#space_info space_info] [@#space space](const path& p); + [@#space_info space_info] [@#space space](const path& p, system::error_code& ec); + + [@#file_status file_status] [@#status status](const path& p); + [@#file_status file_status] [@#status status](const path& p, system::error_code& ec) noexcept; + + bool [@#status_known status_known](file_status s) noexcept; + + [@#file_status file_status] [@#symlink_status symlink_status](const path& p); + [@#file_status file_status] [@#symlink_status symlink_status](const path& p, + system::error_code& ec) noexcept; + + path [@#system_complete system_complete](const path& p); + path [@#system_complete system_complete](const path& p, system::error_code& ec); + + path [@#temp_directory_path temp_directory_path](); + path [@#temp_directory_path temp_directory_path](system::error_code& ec); + + path [@#unique_path unique_path](const path& model="%%%%-%%%%-%%%%-%%%%"); + path [@#unique_path unique_path](system::error_code& ec); + path [@#unique_path unique_path](const path& model, system::error_code& ec); + + path [@#weakly_canonical weakly_canonical](const path& p, const path& base=current_path()); + path [@#weakly_canonical weakly_canonical](const path& p, system::error_code& ec); + path [@#weakly_canonical weakly_canonical](const path& p, const path& base, + system::error_code& ec); + + } // namespace filesystem +} // namespace boost +``` + + + + + +[h2 [#Error-reporting]Error reporting \[fs.err.report\]] + + + +Filesystem library functions often provide two overloads, one that +throws an exception to report file system errors, and another that sets an `error_code`. + + +[: + + +\[['Note:] This supports two common use cases: + + + + * + + +Uses where file system +errors are truly exceptional and indicate a serious failure. Throwing an + exception is the most appropriate response. This is the preferred default for + most everyday programming. + + + * + + +Uses where file system errors are routine and do not necessarily represent + failure. Returning an error code is the most appropriate response. This allows + application specific error handling, including simply ignoring the error. + + + + + +['—end note]\] + + +] + + + + +Functions [*not] having an argument of type `system::error_code&` report errors as follows, unless otherwise specified: + + + + * + + +When a call by the + implementation to an operating system or other underlying API results in an + error that prevents the function from meeting its specifications, an exception + of type `filesystem_error` is thrown. + + + * + + +Failure to allocate storage is reported by throwing an exception as described in the C++ standard, + 17.6.4.10 \[res.on.exception.handling\]. + + + * + + +Destructors throw nothing. + + + + + +Functions having an argument of type `system::error_code&` report errors as follows, unless otherwise + specified: + + + + * + + +If a call by the + implementation to an operating system or other underlying API results in an + error that prevents the function from meeting its specifications, the +`system::error_code&` argument is set as + appropriate for the specific error. Otherwise, `clear()` + is called on the `system::error_code&` argument. + + + * + + +Failure to allocate storage is reported by + throwing an exception as described in the C++ standard, + 17.6.4.10 \[res.on.exception.handling\]. + + + + + +[h2 [#class-path]Class `path` \[class.path\]] + + + +An object of class `path` represents a [@#path path], +and contains a [@#pathname pathname] Such an object is concerned only with the lexical and syntactic aspects +of a path. The path does not necessarily exist in external storage, and the +pathname is not necessarily valid for the current operating +system or for a particular file system. + + + + + + +``` +namespace boost +{ + namespace filesystem + { + class path + { + public: + typedef [*['[@#value_type see below]]] value_type; + typedef std::basic_string string_type; + typedef std::codecvt codecvt_type; + constexpr value_type dot; + constexpr value_type separator; + constexpr value_type preferred_separator; + + // [@#path-constructors constructors] and destructor + path(); + path(const path& p); + path(path&& p) noexcept; + + template + path(Source const& source, const codecvt_type& cvt=codecvt()); + + template + path(InputIterator begin, InputIterator end, + const codecvt_type& cvt=codecvt()); + + ~path(); + + // [@#path-assignments assignments] + path& operator=(const path& p); + path& operator=(path&& p) noexcept; + + template + path& operator=(Source const& source); + + path& assign(const path& p); + path& assign(path&& p) noexcept; + template + path& assign(Source const& source, + const codecvt_type& cvt=codecvt()) + + template + path& assign(InputIterator begin, InputIterator end, + const codecvt_type& cvt=codecvt()); + + // [@#path-appends appends] + path& operator/=(const path& p); + + template + path& operator/=(Source const& source); + + path& append(const path& x); + template + path& append(Source const& source, + const codecvt_type& cvt=codecvt()); + + template + path& append(InputIterator begin, InputIterator end, + const codecvt_type& cvt=codecvt()); + + // [@#path-concatenation concatenation] + path& operator+=(const path& x); + template + path& operator+=(Source const& source); + path& operator+=(value_type x); + template + path& operator+=(CharT x); + + path& concat(const path& x); + template + path& concat(Source const& x, + const codecvt_type& cvt=codecvt()); + template + path& concat(InputIterator begin, InputIterator end, + const codecvt_type& cvt=codecvt()); + + // [@#path-modifiers modifiers] + void [@#path-clear clear](); + path& [@#path-make_preferred make_preferred](); + path& [@#path-remove_filename remove_filename](); + path& [@#path-remove_filename_and_trailing_separators remove_filename_and_trailing_separators](); + path& [@#path-replace_filename replace_filename](const path& replacement); + path& [@#path-replace_extension replace_extension](const path& new_extension = path()); + void [@#path-swap swap](path& rhs) noexcept; + + // lexical operations + path [@#lexically_normal lexically_normal]() const; + path [@#lexically_relative lexically_relative](const path& base) const; + path [@#lexically_proximate lexically_proximate](const path& base) const; + + // [@#path-native-format-observers native format observers] + const string_type& [@#native native]() const noexcept; // native format, encoding + const value_type* [@#c_str c_str]() const noexcept; // native().c_str() + string_type::size_type [@#path-size size]() const noexcept; // native().size() + + template + String [@#string-template string](const codecvt_type& cvt=codecvt()) const; + string [@#string string](const codecvt_type& cvt=codecvt()) const; + wstring [@#wstring wstring](const codecvt_type& cvt=codecvt()) const; + + // [@#path-generic-format-observers generic format observers] + template + String [@#generic_string-template generic_string]() const; + + string [@#generic_string generic_string](const codecvt_type& cvt=codecvt()) const; + wstring [@#generic_wstring generic_wstring](const codecvt_type& cvt=codecvt()) const; + + // [@#path-compare compare] + int [@#path-compare compare](const path& p) const noexcept; + int [@#path-compare compare](const std::string& s) const; + int [@#path-compare compare](const value_type* s) const; + + // [@#path-decomposition decomposition] + path [@#path-root_name root_name]() const; + path [@#path-root_directory root_directory]() const; + path [@#path-root_path root_path]() const; + path [@#path-relative_path relative_path]() const; + path [@#path-parent_path parent_path]() const; + path [@#path-filename filename]() const; + path [@#path-stem stem]() const; + path [@#path-extension extension]() const; + + // [@#path-query query] + bool [@#path-query empty]() const; + bool [@#filename_is_dot filename_is_dot]() const; + bool [@#filename_is_dot_dot filename_is_dot_dot]() const; + bool [@#path-has_root_name has_root_name]() const; + bool [@#path-has_root_directory has_root_directory]() const; + bool [@#path-has_root_path has_root_path]() const; + bool [@#path-has_relative_path has_relative_path]() const; + bool [@#path-has_parent_path has_parent_path]() const; + bool [@#path-has_filename has_filename]() const; + bool [@#path-has_stem has_stem]() const; + bool [@#path-has_extension has_extension]() const; + bool [@#path-is_absolute is_absolute]() const; + bool [@#path-is_relative is_relative]() const; + + // [@#path-iterators iterators] + class iterator; + typedef iterator const_iterator; + class reverse_iterator; + typedef reverse_iterator const_reverse_iterator; + + iterator begin() const; + iterator end() const; + reverse_iterator rbegin() const; + reverse_iterator rend() const; + + // [@#path-imbued-locale imbued locale] + static std::locale [@#path-imbue imbue](const std::locale& loc); + static const codecvt_type & [@#path-codecvt codecvt](); + + private: + string_type pathname; // [*['exposition only]] + }; + + } // namespace filesystem +} // namespace boost +``` + + + + + + +`[#value_type]value_type` is a `typedef` for the +character type used by the operating system to represent pathnames. + + + + + +[h3 [#path-Usage]`path` Usage concerns \[path.usage\]] + + + +[h4 Multithreading concerns] + + + + +Filesystem library functions are not protected against data races. \[Modifying +an object of a Filesystem library type that is shared between threads risks +undefined behavior unless objects of that type are explicitly specified as being +sharable without data races or the user supplies a locking mechanism. ['—end +note]\] \[['Note:] Thus the Filesystem library behaves as if it were part +of the standard library, and C++ standard 17.6.4.10 ['Shared objects and the +library] \[res.on.objects\] would thus apply.  ['—end note]\] + + + + +[h4 Windows concerns] + + + + +Visual C++ at least through version 2012 does not employ C++11-style static +initialization locks, so the initialization of `path::codecvt()` can +race, either with itself or `path::imbue()` if they are called from +a different thread. A workaround is to call: + + + +[: + + +`path::codecvt();  // ensure VC++ does not race during +initialization.` + + + +] + + + + +in the main thread before launching any additional threads. \[['Note:] The +obvious fix of the Filesystem implementation doing the locking doesn't work +because of unrelated problems with the Microsoft compiler; for static linking +the runtime tries to do the initialization before main() starts, but doesn't +permit operating system lock calls at that time.  ['—end note]\] + + + + +[h4 POSIX concerns] + + + + +Filesystem library initialization may throw an exception on POSIX +systems (e.g. Linux, but not Mac OS X) that use environmental variables to +determine the encoding of paths. This happens when `std::locale("")` +throws because an environmental variable such as LANG is set to an invalid +value, so it can affect any use of  `std::locale("")`, not just +the Filesystem library. Filesystem uses lazy initialization so the exception is +only thrown if a valid `std::locale("")` is actually needed, and also +so that the exception is thrown after `main()` starts. + + + + + +Rather than waiting until a call to some Filesystem library function +unexpectedly triggers the exception when it calls `path::codecvt()`, +a program that needs be highly robust against environmental variable problems +may want to preemptively call `std::locale("")` within a try block, +catch the exception, and diagnose or repair the invalid environmental variable. + + + + +[h3 [#path-Conversions]`path` Conversions \[path.cvt\]] + + +[h4 `path` argument conversions \[[#path.arg.convert]path.arg.cvt\]] + + +[h5 [#path-Conversions-to-native-format]`path` argument +format conversions \[path.arg.fmt.cvt\]] + + + +Member function arguments that take character sequences representing paths +may use the [@#generic-pathname-format generic pathname format] or +the [@#native-pathname-format native pathname format]. Iff such arguments +are in the generic format and the generic format is not acceptable to the +operating system as a native path, conversion to native format shall be performed +during the processing of the argument. See \[[@#Operating-system-examples fs.os.examples]\]. + + +[: + + +\[['Note:] Depending on the operating system, there may be no unambiguous way for an implementation to +always be able to distinguish between native format and generic format arguments. +This is by design as it simplifies use for operating systems that do not require +disambiguation. Should an implementation encounter an +operating system where disambiguation is required, an implementation can defined +an extension to distinguish between the formats.[' +—end note]\] + + +] + + + + + +If the native format requires +paths for regular files to be formatted differently from paths for directories, the +path shall be treated as a directory path if last element is a separator, +otherwise it shall be treated as a regular file path. + + + + +[h5 [#path-Encoding-conversions]` +path` argument encoding conversions +\[path.arg.encoding.cvt\]] + + + +For member function arguments that take character sequences representing +paths, if the value type of the argument is not `value_type` and one +of the value types is `char` and the other is `wchar_t`, conversion to `value_type` +shall be performed by the `path::codecvt()` facet. (\[[@#path-imbued-locale path.imbued.locale]\]). + + + +[h4 [#path-Conversions-to-generic-format]`path` Conversions +to generic format \[fs.cvt.to.generic\]] + + + +[@#path-generic-format-observers Generic format observer] functions +shall return strings formatted according to the [@#generic-pathname-format generic pathname format] +using ['preferred-separator]. See \[[@#Operating-system-examples fs.os.examples]\]. + + + +[h3 [#path-Requirements]`path` Requirements \[path.req\]] + + + +Template parameters named `[#InputIterator]InputIterator` are required to meet the +requirements for a C++ standard library `InputIterator` compliant iterator. The iterator's value type is required +to be one of: `char`, `wchar_t`. Collectively, these types are referred to as supported path character types. + + + + +Template parameters named `[#Source]Source` are required to be one of: + + + + * + + +A `std::basic_string`, `std::basic_string_view`, `boost::container::basic_string` or `boost::basic_string_view` specialization with a value type of one of the supported path character types. + + + * + + +[*v3, deprecated:] A container with a value type of one of the supported path character types. + + + * + + +A pointer into a null terminated string. The value type is required + to be a supported path character type. + + + * + + +A C-array of supported path character type containing a null terminated string. + + + * + + +A `boost::filesystem::directory_entry`. + + + + + +[h3 [#path-constructors]`path` constructors \[path.construct\]] + + + +``` +template +path(Source const& source, const codecvt_type& cvt=codecvt()); +``` + + + + +``` +template +path(InputIterator begin, InputIterator end, const codecvt_type& cvt=codecvt()); +``` + + +[: + + +['Effects:] Stores the contents \[`begin`,`end`) + of `source` in `pathname`, converting format and + encoding if required (\[[@#path.arg.convert path.arg.convert]\]). + + +] + + + +[h3 [#path-assignments] ` +path` assignments \[path.assign\]] + + + +``` +path& operator=(const path& p); +path& operator=(path&& p) noexcept; +template +path& operator=(Source const& source); +path& assign(const path& p); +path& assign(path&& p) noexcept; +template +path& assign(Source const& source, const codecvt_type& cvt=codecvt()); +template +path& assign(InputIterator begin, InputIterator end, const codecvt_type& cvt=codecvt()); +``` + + +[: + + +['Effects:] Stores the contents \[`begin`,`end`) + or `source` or `p` in `pathname`, converting format and + encoding if required (\[[@#path.arg.convert path.arg.convert]\]). + + + + + + ['Returns: ]`*this` + + + ] + + + +[h3 [#path-appends]`path` appends +\[path.append\]] + + + +The append operations use ` + operator/=` to denote their semantic effect of appending [' + preferred-separator] when needed. + + + + +``` +path& operator/=(const path& p); +path& append(const path& p); +``` + + +[: + + +['Effects:] + + + [: + + +[*v3:] Appends `path::preferred_separator` to `pathname`, + converting format and encoding if required (\[[@#path.arg.convert path.arg.convert]\]), unless: + + + + * + + +an added separator + would be redundant, or + + + * + + +would change a relative path to an absolute path, or + + + * + + +`p.empty()`, or + + + * + + +`*p.native().cbegin()` is a directory separator. + + + + + +Then appends `p.native()` to `pathname`. + + + + +[*v4:] If `p.[@#path-is_absolute is_absolute]() || (p.[@#path-has_root_name has_root_name]() && p.[@#path-root_name root_name]() != [@#path-root_name root_name]())`, assigns `p` to `*this`. Otherwise, modifies `*this` as if by these steps: + + + + * If `p.[@#path-has_root_name has_root_directory]()`, removes root directory and relative path, if any. + * Let `x` be a `path` with contents of `p` without a root name. If `[@#path-has_filename has_filename]()` is `true` and `x` does not start with a directory separator, appends `path::preferred_separator`. + * Appends `x.native()`. + + + + +\[['Note:] Whether the path is absolute or not depends on the target OS conventions. Because of this, the result of append operation may be different for different operating systems for some paths. For example, `path("//net/foo") / "/bar"` will result in `"/bar"` on POSIX systems and `"//net/foo/bar"` on Windows because `"/bar"` is an absolute path on POSIX systems but not on Windows. For portable behavior avoid appending paths with non-empty [@#path-root_path root path]. ['—end note]\] + + + ] + + + + +['Returns: ]`*this` + + +] + + + + +``` +template +path& operator/=(Source const & source); +template +path& append(Source const & source, const codecvt_type& cvt=codecvt()); +template +path& append(InputIterator begin, InputIterator end, const codecvt_type& cvt=codecvt()); +``` + + + [: + + +['Effects:] + + + [: + + +As if `append(path(['args]))`, where `['args]` is the list of arguments passed to the operation. + + + ] + + + + +['Returns: ]`*this` + + + ] + + + + +[h3 [#path-concatenation]`path` concatenation \[path.concat\]] + + + +``` +path& operator+=(const path& p); +path& operator+=(value_type x); +template +path& operator+=(Source const& source); +template +path& operator+=(CharT x); +path& concat(const path& p); +template +path& concat(Source const& source, const codecvt_type& cvt=codecvt()); +template +path& concat(InputIterator begin, InputIterator end, const codecvt_type& cvt=codecvt()); +``` + + +[: + +['Postcondition:] `native() == prior_native + ['effective-argument]`, + where `prior_native` is `native()` prior to the call to `operator+=`, + and `['effective-argument]` is: + + + * + + +`p.native()` if `p` is present and is `const path&`, otherwise + + + * + + +`s`, where `s` is + `std::basic_string::value_type> +s(begin, end)`, + if `begin` and `end` arguments are present, otherwise + + + * + + +`x`. + + + + + +If the value type of `['effective-argument]` would not be `path::value_type`, the actual argument or argument range is first + converted so that `['effective-argument]` has value type `path::value_type`. + + + + +['Returns: ]`*this` + + + ] + + + +[h3 [#path-modifiers] ` +path` modifiers \[path.modifiers\]] + + + +``` +void [#path-clear]clear(); +``` + + +[: + + +['Postcondition:] `this->empty()` is true. + + +] + + + + +``` +path& [#path-make_preferred]make_preferred(); +``` + + +[: + + +['Effects:] ['directory-separator]s are converted to ['preferred-separator]s. + See \[[@#Operating-system-examples fs.os.examples]\]. + + + + +['Returns:] `*this` + + +] + + + + + + +``` +path& [#path-remove_filename]remove_filename(); +``` + + +[: + + +['Effects:] [*v3:] As if, `*this = parent_path();` + + + + +\[['Note:] This function is needed to efficiently implement `directory_iterator`. It is exposed to allow additional uses. The actual + implementation may be much more efficient than `*this = parent_path()`  ['—end + note]\] + + + + +[*v4:] Removes the `filename()` path element. + + + + +\[['Note:] Unlike [*v3], the trailing directory separator(s) are not removed.['—end + note]\] + + + + +['Returns:] `*this`. + + +] + + + + +``` +path& [#path-remove_filename_and_trailing_separators]remove_filename_and_trailing_separators(); +``` + + +[: + + +['Effects:] As if, `*this = parent_path();` + + + + +\[['Note:] This function is similar to `path::remove_filename` from [*v3], but is also usable in [*v4].['—end + note]\] + + + + +['Returns:] `*this`. + + +] + + + + +``` +path& [#path-replace_filename]replace_filename(const path& replacement); +``` + + +[: + + +['Effects:] As if, `remove_filename().append(replacement);` + + + + +['Returns:] `*this`. + + +] + + + + +``` +path& [#path-replace_extension]replace_extension(const path& new_extension = path()); +``` + + +[: + + +['Effects:] + + + + * + + +Any existing `extension()` is removed from the stored path, + then + + + * + + +iff + `new_extension` is not empty and does not begin with a dot + character, a dot character is appended to the stored path, then + + + * + + + + `new_extension` is appended to the stored path. + + + + + +['Returns:] `*this` + + +] + + + + +``` +void [#path-swap]swap(path& rhs) noexcept; +``` + + +[: + + +['Effects:] Swaps the contents of the two paths. + + + + +['Complexity:] constant time. + + +] + + + + +[h3 [#path-lexical-operations]`path` lexical operations + \[path.lex.ops\]] + + +``` +path [#lexically_normal]lexically_normal() const; +``` + +[: + + +['Overview:] Returns `*this` with redundant current directory +(['dot]), parent directory (['dot-dot]), and ['directory-separator] elements removed. + + + + +['Returns:] `*this` in [@#normal-form normal form]. + + + + +['Remarks:] Uses `operator/=` to compose the returned path. + + + + +\[['Example:] + + + + + + + +``` +std::cout << path("foo/./bar/..").lexically_normal() << std::endl; // outputs "foo" +std::cout << path("foo/.///bar/../").lexically_normal() << std::endl; // v3: outputs "foo/." + // v4: outputs "foo/" +``` + + + +On Windows, the +returned path's ['directory-separator] characters will be backslashes rather than slashes, but that +does not affect `path` equality.[' —end example]\] + + +] + + + + +``` +path [#lexically_relative]lexically_relative(const path& base) const; +``` + + [: + + +['Overview:] Returns `*this` made relative to `base`. + Treats empty or identical paths as corner cases, not errors. Does not resolve + symlinks. Does not first normalize `*this` or `base`. + + + + + +['Remarks:] Uses `std::mismatch(begin(), end(), base.begin(), base.end())`, to determine the first mismatched element of + `*this` and `base`. Uses `operator==` to + determine if elements match. + + + + + +['Returns:] + + + + + * + `path()` if the first mismatched element of `*this` is equal to ` + begin()` or the first mismatched element + of `base` is equal to `base.begin()`, or +  + + * + `path(".")` if the first mismatched element of ` + *this` is equal to ` + end()` and the first mismatched element + of `base` is equal to `base.end()`, or +  + + * An object of class `path` composed via application of ` + operator/= path("..")` for each element in the half-open + range \[first + mismatched element of `base`, `base.end()`), and then + application of `operator/=` for each element in the half-open + range + \[first mismatched element of `*this`, `end()`). + + + + + +\[['Example:] + + + + +`assert(path("/a/d").lexically_relative("/a/b/c") == "../../d"); + +assert(path("/a/b/c").lexically_relative("/a/d") == "../b/c"); + +assert(path("a/b/c").lexically_relative("a") == "b/c"); + +assert(path("a/b/c").lexically_relative("a/b/c/x/y") == "../.."); + +assert(path("a/b/c").lexically_relative("a/b/c") == "."); + +assert(path("a/b").lexically_relative("c/d") == "");` + + + + +The above assertions will succeed.[' ]On Windows, the +returned path's ['directory-separator]s will be backslashes rather than +forward slashes, but that +does not affect `path` equality. ['—end example]\] + + + + + +\[['Note:] If symlink following semantics are desired, use the operational function ` + [@#relative relative]`  ['—end note]\] + + + + + +\[['Note:] If [@#lexically_normal normalization] is needed to ensure + consistent matching of elements, apply `[@#lexically_normal lexically_normal()]` + to `*this`, `base`, or both. ['—end note]\] + + +] + + + + +``` +path [#lexically_proximate]lexically_proximate(const path& base) const; +``` + +[: + + +['Returns:] If `lexically_relative(base)` returns a non-empty path, returns that path. +Otherwise returns `*this`. + + + + + +\[['Note:] If symlink following semantics are desired, use the operational function ` + [@#relative relative]`  ['—end note]\] + + + + + +\[['Note:] If [@#lexically_normal normalization] is needed to ensure + consistent matching of elements, apply `[@#lexically_normal lexically_normal()]` + to `*this`, `base`, or both. ['—end note]\] + + + +] + + + + + +[h3 [#path-native-format-observers]`path` native format observers +\[path.native.obs\]] + + + +The string returned by all native format observers is in the [@#native-pathname-format native pathname format]. + + + + +``` +const string_type& [#native]native() const noexcept; +``` + + +[: + + +['Returns:] `pathname`. + + +] + + + + +``` +const value_type* [#c_str]c_str() const noexcept; +``` + + +[: + + +['Returns:] `pathname.c_str()`. + + +] + + + + +``` +string_type::size_type [#path-size]size() const noexcept; +``` + + +[: + + +['Returns:] `pathname.size()`. + + +] + + + + +``` +template +String [#string-template]string(const codecvt_type& cvt=codecvt()) const; +``` + + +[: + + +['Returns:] `pathname`. + + + + +['Remarks:] If `string_type` is a different type than `String`, conversion is performed by `cvt`. + + +] + + + + +``` +string [#string]string(const codecvt_type& cvt=codecvt()) const; +wstring [#wstring]wstring(const codecvt_type& cvt=codecvt()) const; +``` + + +[: + + +['Returns:] `pathname`. + + + + +['Remarks:] If `string_type` is a different type than +function's return type, conversion is performed by `cvt`. + + +] + + + + +[h3 [#path-generic-format-observers]`path` generic format observers +\[path.generic.obs\]] + + + +The string returned by all generic format observers is in the [@#generic-pathname-format generic pathname format]. +The returned strings use a single forward slash ('/') as directory separators. + + + + +``` +template +String [#generic_string-template]generic_string(const codecvt_type& cvt=codecvt()) const; +``` + + +[: + + +['Returns:] `pathname`. + + + + +['Remarks:] If `string_type` is a different type than `String`, conversion is performed by `cvt`. + + +] + + + + +``` +string [#generic_string]generic_string(const codecvt_type& cvt=codecvt()) const; +wstring [#generic_wstring]generic_wstring(const codecvt_type& cvt=codecvt()) const; +``` + + +[: + + +['Returns:] `pathname`. + + + + +['Remarks:] If `string_type` is a different type than +function's return type, conversion is performed by `cvt`. + + +] + + + + +[h3 [#path-compare]`path` compare \[path.compare\]] + + + +``` +int compare(const path& p) const noexcept; +``` + + +[: + + +['Returns:] A value less than 0 if the elements of `*this` are lexicographically less than the elements of `p`, otherwise a + value greater than 0 if the elements of `*this` are + lexicographically greater than the elements of `p`, otherwise 0. + + + + +Remark: The elements are determined as if by iteration over the half-open + range \[`begin()`, `end()`) for `*this` and `p`. + + +] + + + + +``` +int compare(const std::string& s) const +``` + + +[: + + +['Returns:] `compare(path(s))`. + + +] + + + + +``` +int compare(const value_type* s) const +``` + + +[: + + +['Returns:] `compare(path(s))`. + + +] + + + +[h3 [#path-decomposition] `path` decomposition +\[path.decompose\]] + + + +['See the [@#path-decomposition-table Path decomposition table] for examples +for values returned by decomposition functions. The [@tutorial.html#Using-path-decomposition Tutorial] may also be +helpful.] + + + + +``` +path [#path-root_name]root_name() const; +``` + + +[: + + +['Returns:] ['root-name,] if `pathname` includes ['root-name], otherwise `path()`. + + +] + + + + +``` +path [#path-root_directory]root_directory() const; +``` + + +[: + + +['Returns:] ['root-directory], if `pathname` includes ['root-directory], otherwise `path()`. + + + + +If ['root-directory] is composed of ['slash name], ['slash] is +excluded from the returned string. + + +] + + + + +``` +path [#path-root_path]root_path() const; +``` + + +[: + + +['Returns:] `[@#path-root_name root_name]() / [@#path-root_directory root_directory]()` + + +] + + + + +``` +path [#path-relative_path]relative_path() const; +``` + + +[: + + +['Returns:] A `path` composed from `pathname`, if `!empty()`, beginning +with the first ['filename] after ['root-path]. Otherwise, `path()`. + + +] + + + + +``` +path [#path-parent_path]parent_path() const; +``` + + +[: + + +['Returns:] `(empty() || begin() == --end()) ? path() : ['pp]`, where `['pp]` is constructed as if by + starting with an empty `path` and successively applying `operator/=` for each element in the range `begin()`, `--end()`. + + + + +\[['Example:] + + + [: + + +``` +std::cout << path("/foo/bar.txt").parent_path(); // outputs "/foo" +std::cout << path("/foo/bar").parent_path(); // outputs "/foo" +std::cout << path("/foo/bar/").parent_path(); // outputs "/foo/bar" +std::cout << path("/").parent_path(); // outputs "" +std::cout << path(".").parent_path(); // outputs "" +std::cout << path("..").parent_path(); // outputs "" +``` + + + ] + + + + + See the last bullet item in the [@#path-iterators + forward traversal order] list for why the `"/foo/bar/"` example + doesn't output `"/foo"`. + + + + + ['—end example]\] + + +] + + + + +``` +path [#path-filename]filename() const; +``` + + +[: + + +['Returns:] [*v3:] `empty() ? path() : *--end()` + + [*v4:] `*this == [@#path-root_path root_path]() ? path() : *--end()` + + + + +\[['Example:] + + + [: + + +``` +std::cout << path("/foo/bar.txt").filename(); // outputs "bar.txt" +std::cout << path("/foo/bar").filename(); // outputs "bar" +std::cout << path("/foo/bar/").filename(); // v3 outputs "." + // v4 outputs "" +std::cout << path("/").filename(); // v3 outputs "/" + // v4 outputs "" +std::cout << path(".").filename(); // outputs "." +std::cout << path("..").filename(); // outputs ".." +``` + + + ] + + + + + See the last bullet item in the [@#path-iterators + forward traversal order] list for why the `"/foo/bar/"` example + doesn't output `"bar"`. + + + + + ['—end example]\] + + +] + + + + +``` +path [#path-stem]stem() const; +``` + + +[: + + +['Returns:] If `p.[@path-filename filename]()` does not contain dots, consist solely of one + or to two dots, ['\[Since [*v4]:] or contains exactly one dot as the initial character,['\]] returns `p.filename()`. + Otherwise returns the substring of `p.filename()` starting at its beginning and + ending at the last dot (the dot is not included). + + + + +\[['Example:] + + + [: + + +``` +std::cout << path("/foo/bar.txt").stem() << '\\n'; // outputs "bar" +std::cout << path(".hidden").stem() << '\\n'; // v3 outputs "" + // v4 outputs ".hidden" +path p = "foo.bar.baz.tar"; +for (; !p.extension().empty(); p = p.stem()) + std::cout << p.extension() << '\\n'; + // outputs: .tar + // .baz + // .bar +``` + + + ] + + + + + ['—end example]\] + + +] + + + + +``` +path [#path-extension]extension() const; +``` + + +[: + + +['Returns:] The substring of `p.[@path-filename filename]()` that is not included + in `p.[@#path-stem stem]()`. + + + + +['Remarks:] Implementations are permitted but not required to define additional + behavior for file systems which append additional elements to extensions, such + as alternate data streams or partitioned dataset names. + + + + +\[['Example:] + + + [: + + +``` +std::cout << path("/foo/bar.txt").extension(); // outputs ".txt" +``` + + + ] + + + + + ['—end example]\] + + + + +\[['Note:[* ]]The dot is included in the return value so that it is + possible to distinguish between no extension and an empty extension. + See [@https://lists.boost.org/Archives/boost/2010/02/162028.php + https://lists.boost.org/Archives/boost/2010/02/162028.php] for more + extensive rationale.  ['—end note]\] + + +] + + + +[h3 [#path-query] `path` query \[path.query\]] + + + +``` +bool [#path-empty]empty() const; +``` + + +[: + + +['Returns:] `m_pathname.empty()`. + + +] + + + + +``` +bool [#filename_is_dot]filename_is_dot() const; +``` + + +[: + + +['Returns:] `filename() == path(".")` + + + + +\[['Example:] + + + [: + + +``` +std::cout << path(".").filename_is_dot(); // outputs 1 +std::cout << path("/.").filename_is_dot(); // outputs 1 +std::cout << path("foo/.").filename_is_dot(); // outputs 1 +std::cout << path("foo/").filename_is_dot(); // v3 outputs 1, v4 outputs 0 +std::cout << path("/").filename_is_dot(); // outputs 0 +std::cout << path("/foo").filename_is_dot(); // outputs 0 +std::cout << path("/foo.").filename_is_dot(); // outputs 0 +std::cout << path("..").filename_is_dot(); // outputs 0 +``` + + + ] + + + + + See the last bullet item in the [@#path-iterators forward traversal order] + list for why `path("foo/").filename()` is a dot filename in [*v3]. + + + + + ['—end example]\] + + +] + + + + +``` +bool [#filename_is_dot_dot]filename_is_dot_dot() const; +``` + + +[: + + +['Returns:] `filename() == path("..")` + + +] + + + + +``` +bool [#path-has_root_path]has_root_path() const; +``` + + +[: + + +['Returns:] `![@#path-root_path root_path]().empty()` + + +] + + + + +``` +bool [#path-has_root_name]has_root_name() const; +``` + + +[: + + +['Returns:] `![@#path-root_name root_name]().empty()` + + +] + + + + +``` +bool [#path-has_root_directory]has_root_directory() const; +``` + + +[: + + +['Returns:] `![@#path-root_directory root_directory]().empty()` + + +] + + + + +``` +bool [#path-has_relative_path]has_relative_path() const; +``` + + +[: + + +['Returns:] `![@#path-has_relative_path relative_path]().empty()` + + +] + + + + +``` +bool [#path-has_parent_path]has_parent_path() const; +``` + + +[: + + +['Returns:] `![@#path-parent_path parent_path]().empty()` + + +] + + + + +``` +bool [#path-has_filename]has_filename() const; +``` + + +[: + + +['Returns:] `![@#path-filename filename]().empty()` + + +] + + + + +``` +bool [#path-has_stem]has_stem() const; +``` + + +[: + + +['Returns:] `![@#path-stem stem]().empty()` + + +] + + + + +``` +bool [#path-has_extension]has_extension() const; +``` + + +[: + + +['Returns:] `![@#path-has_extension extension]().empty()` + + +] + + + + +``` +bool [#path-is_absolute]is_absolute() const; +``` + + +[: + + +['Returns:] `true` if the elements of `[@#path-root_path root_path]()` uniquely identify a directory, else `false`. + + + + +\[['Note:] Path is considered absolute on POSIX systems if it has a [@#path-root_directory root directory], and on Windows - if it has both [@#path-root_name root name] and [@#path-root_directory root directory]. ['—end note]\] + + +] + + + + +``` +bool [#path-is_relative]is_relative() const; +``` + + +[: + + +['Returns:] `![@#path-is_absolute is_absolute]()`. + + +] + + + +[h3 [#path-iterators] ` +path` iterators \[path.itr\]] + + + + Path iterators `iterator`, `const_iterator`, +`reverse_iterator`, and `const_reverse_iterator` iterate over the elements of the stored pathname. + + + + + Path iterators are constant iterators satisfying +the requirements of a bidirectional iterator (C++ Std, 24.1.4 Bidirectional +iterators \[lib.bidirectional.iterators\]). The `value_type`  of +an iterator is `path`. + + + [: + + + \[['Note:] Path iterators store their value objects internally +and when dereferenced return references to those internal objects. They cannot +be used with iterator adaptors such as `std::reverse_iterator` that +assume references obtained by dereferencing an iterator point to objects that +out-live the iterator itself. ['—end note]\] + + +] + + + + +Calling any non-const member function of a `path` object + invalidates all iterators referring to elements of that object. + + + + + The forward traversal order is as follows: + + + + * The ['root-name] element, if present. + * The ['root-directory] element, if present, in the generic format. + \[['Note:] the generic format is required to ensure lexicographical + comparison works correctly. ['—end note]\] + * Each successive ['filename] element, if present. + * \[[*v3:] ['Dot]\] \[[*v4:] Empty path\], if one or more trailing non-root directory separators + are present. + + [: + + +\[['Note:] Treating the last element during iteration as \[[*v3:] ['dot]\] \[[*v4:] an empty path\] when + there is a trailing directory separator enables lexical (i.e. syntactic) + distinction between paths to directories versus paths to regular files. Such a + distinction is usually irrelevant on POSIX and Windows based operating + systems, but may be a requirement on other operating systems. ['—end note]\] + + + ] + + + + +The backward traversal order is the reverse of forward traversal. + + + +``` +iterator begin() const; +``` + +[: + + +['Returns:] An iterator for the first element in forward traversal + order. If no elements are present, the end iterator. + + +] + + + +``` +iterator end() const; +``` + +[: + + +['Returns:] The end iterator. + + +] + + + +``` +reverse_iterator rbegin() const; +``` + +[: + + +['Returns:] An iterator for the first element in backward traversal + order. If no elements are present, the end iterator. + + +] + + + +``` +reverse_iterator rend() const; +``` + +[: + + +['Returns:] The end iterator. + + +] + + + +[h3 [#path-imbued-locale]` path` + imbued locale \[path.imbued.locale\]] + + + +`path` operations sometimes require encoding conversions between + `pathname` and some other string object where one of the value types + is `char` and the other is `wchar_t`. Such conversions + shall be performed by the `path::codecvt()` facet. + + + [: + + +\[['Example:] + ... ['—end example]\] + + + ] + + + +``` +static std::locale [#path-imbue]imbue(const std::locale& loc); +``` + +[: + + +['Effects:] Stores a copy of `loc` as the imbued `path` + locale. + + + + +['Returns:] The previous imbued `path` locale. + + + + +['Remarks:] The initial value of the imbued `path` locale is + operating system dependent. It shall be a locale with a `codecvt` + facet for a `char` string encoding appropriate for the operating + system. See (\[[@#Operating-system-examples fs.os.examples]\]).  + + +] + + + +``` +static const codecvt_type& [#path-codecvt]codecvt(); +``` + +[: + + +['Returns:] The `codecvt` facet for the imbued` path` + locale . + + +] + + + + + +[h3 [#path-non-member-functions] `path` non-member functions +\[path.non-member\]] + + + +``` +bool lexicographical_compare(path::iterator first1, path::iterator last1, + path::iterator first2, path::iterator last2); +``` + +[: + + +['Returns:] `true` if the sequence of `native()` strings for the elements defined by the half-open range `\[first1, last1)` is + lexicographically less than the sequence of `native()` strings for + the elements defined by the half-open range `\[first2, last2)`. Returns `false` otherwise. + + + + +['Remarks:] If two sequences have the same number of elements and their + corresponding elements are equivalent, then neither sequence is + lexicographically less than the other. If one sequence is a prefix of the + other, then the shorter sequence is lexicographically less than the longer + sequence. Otherwise, the lexicographical comparison of the sequences yields + the same result as the comparison of the first corresponding pair of elements + that are not equivalent. + + + + +\[['Note:] A `path` aware `lexicographical_compare` algorithm is provided for historical reasons. ['—end note]\] + + +] + + + + + + +``` +path [#lex-normal]lexically_normal(const path& p); +``` + + + + +[: + + +['Overview:] Returns `p` with redundant current + directory (['dot]), parent directory (['dot-dot]), and [' + directory-separator] elements removed. + + + + +['Returns:] `p` in + [@#normal-form + normal form]. + + + + +['Remarks:] Uses `operator/=` to compose the + returned path. + + + + +\[['Example:] + + + + +`assert(lexically_normal("foo/./bar/..") == "foo"); + + assert(lexically_normal("foo/.///bar/../") == "foo/.");` + + + + +All of the above assertions will succeed.[' ]On Windows, the + returned path's ['directory-separator] characters will be backslashes + rather than slashes, but that does not affect `path` equality. + ['—end example]\] + + +] + + + + + + +``` +path [#lex-relative]lexically_relative(const path& p, const path& base); +``` + + + + +[: + + +['Overview:] Returns `p` made relative to ` + base`. Treats empty or identical paths as corner cases, not errors. Does + not resolve symlinks. Does not first normalize `p` or `base`. + + + + +['Remarks:] Uses `std::mismatch(p.begin(), p.end(), + base.begin(), base.end())`, to determine the first mismatched element of + `p` and `base`. Uses `operator==` to + determine if elements match. + + + + +['Returns:] + + + + * + + +`path()` if the first mismatched element of `p` + is equal to `p.begin()` or the first mismatched element of ` + base` is equal to `base.begin()`, or + +   + + + * + + +`path(".")` if the first mismatched element of ` + p` is equal to `p.end()` and the first mismatched element + of `base` is equal to `base.end()`, or + +   + + + * + + +An object of class `path` composed via application + of `operator/= path("..")` for each element in the half-open + range \[first mismatched element of `base`, `base.end()`), + and then application of `operator/=` for each element in the + half-open range \[first mismatched element of `p`, `p.end()`). + + + + + + +\[['Example:] + + + + +`assert(lexically_relative("/a/d", "/a/b/c") == "../../d"); + + assert(lexically_relative("/a/b/c", "/a/d") == "../b/c"); + + assert(lexically_relative("a/b/c", "a") == "b/c"); + + assert(lexically_relative("a/b/c", "a/b/c/x/y") == "../.."); + + assert(lexically_relative("a/b/c", "a/b/c") == "."); + + assert(lexically_relative("a/b", "c/d") == "");` + + + + +All of the above assertions will succeed.[' ]On Windows, the + returned path's ['directory-separator]s will be backslashes rather than + forward slashes, but that does not affect `path` equality.[' —end + example]\] + + + + +\[['Note:] If symlink following semantics are desired, use the + operational function ` + [@#relative + relative]`  ['—end note]\] + + + + +\[['Note:] If [@#normal-form normalization] is needed to ensure consistent matching of elements, wrap + `p`, `base`, or both in calls ` + [@#lex-normal lexically_normal]()`. ['—end note]\] + + +] + + + +``` +void swap(path& lhs, path& rhs) noexcept; +``` + +[: + + +['Effects: ]`lhs.swap(rhs)`. + + +] + + + +``` +std::size_t [#hash_value]hash_value(const path& p); +``` + +[: + + +['Returns:] A hash value for the path `p`. If + for two paths, `p1 == p2` then `hash_value(p1) == hash_value(p2)`. + + + + +This allows paths to be used with [@../../functional/hash/index.html Boost.Hash]. + + +] + + + +``` +bool operator< (const path& lhs, const path& rhs); +``` + +[: + + +['Returns:] `return lhs.compare(rhs.begin) < 0`. + + +] + + + +``` +bool operator<=(const path& lhs, const path& rhs); +``` + +[: + + +['Returns:] `!(rhs < lhs)`. + + +] + + + +``` +bool operator> (const path& lhs, const path& rhs); +``` + +[: + + +['Returns:] `rhs < lhs`. + + +] + + + +``` +bool operator>=(const path& lhs, const path& rhs); +``` + +[: + + +['Returns:] `!(lhs < rhs)`. + + +] + + + +``` +bool operator==(const path& lhs, const path& rhs); +``` + +[: + + +['Returns:] `!(lhs < rhs) && !(rhs < lhs)`. + + + + +\[['Note:] [#Path-equality]Path equality and path + equivalence have different semantics. + + + + +Equality is determined by the `path` non-member `operator==`, which considers the two path's lexical + representations only. Thus `path("foo") == "bar"` is never `true`. + + + + +Equivalence is determined by the `[@#equivalent equivalent]()` non-member function, which determines if two paths [@#path resolve] to the same file system entity. + Thus `equivalent("foo", "bar")` will be `true` when both paths resolve to the same file. + + + + +Programmers wishing to determine if two paths are "the same" must decide if + "the same" means "the same representation" or "resolve to the same actual + file", and choose the appropriate function accordingly. ['—end note]\] + + +] + + + +``` +bool operator!=(const path& lhs, const path& rhs); +``` + +[: + + +['Returns:] `!(lhs == rhs)`. + + +] + + + +``` +path operator/ (const path& lhs, const path& rhs); +``` + +[: + + +['Returns:] `path(lhs) /= rhs`. + + +] + + + +[h3 [#path-non-member-operators]`path`[#path-inserter-extractor] inserter + and extractor \[path.io\]] + + + + The inserter and extractor delimit the string with double-quotes (`"`) +so that paths with embedded spaces will round trip correctly. Ampersand (`&`) +is as an escape character, so the path can itself contain double quotes. + + + +``` +template +std::basic_ostream& operator<<(std::basic_ostream& os, + const path& p); + +``` + +[: + + +['Effects: ]Insert characters into `os`: + + + + * + + +A double-quote. + + + + * + + +Each character in `p.string>()`. + If the character to be inserted is equal to the escape character or a + double-quote, as determined by `operator==`, first insert the + escape character. + + + + * + + +A double-quote. + + + + + + +\[['Note:] Effects are similar to: + + + +``` +std::basic_string str(p.string>()); +os << [@../../io/doc/quoted_manip.html boost::io::quoted](str, static_cast('&')); +``` + +['—end note]\] + + +['Returns:] `os` + + +] + + + +``` +template +std::basic_istream& operator>>(std::basic_istream& is, + path& p); + +``` + +[: + + +['Effects:  ]Extract characters from `is`: + + + + * If the first character that would be extracted is equal to double-quote, + as determined by `operator==`, then: + * Discard the initial double-quote. + * Save the value and then turn off the `skipws` flag. + * `p.clear()` + * Until an unescaped double-quote character is reached or ` + is.not_good()`, extract characters from `is` and append + them to `p`, except that if an escape character is reached, + ignore it and append the next character to `p`. + * Discard the final double-quote character. + * Restore the `skipws` flag to its original value. + + + * Otherwise, `is >> p`. + + + +\[['Note:] Effects are similar to: + + + +``` +std::basic_string str; +is >> [@../../io/doc/quoted_manip.html boost::io::quoted](str, static_cast('&')); +p = str; +``` +['—end note]\] + + +['Returns:] `is` + + + ] + + + +[h2 [#Class-filesystem_error]Class `filesystem_error` +\[class.filesystem_error\]] + + +``` +namespace boost +{ + namespace filesystem + { + class filesystem_error : public system_error + { + public: + filesystem_error(); + filesystem_error(const filesystem_error&); + [@#filesystem_error-2-arg filesystem_error](const std::string& what_arg, + system::error_code ec); + [@#filesystem_error-3-arg filesystem_error](const std::string& what_arg, + const path& p1, system::error_code ec); + [@#filesystem_error-4-arg filesystem_error](const std::string& what_arg, + const path& p1, const path& p2, system::error_code ec); + + filesystem_error& filesystem_error(const filesystem_error&); + ~filesystem_error(); + + filesystem_error& operator=(const filesystem_error&); + + const path& [@#filesystem_error-path1 path1]() const; + const path& [@#filesystem_error-path2 path2]() const; + + const char * [@#filesystem_error-what what]() const; + }; + } // namespace filesystem +} // namespace boost +``` + + + +The class template `filesystem_error` defines the type of +objects thrown as exceptions to report file system errors from functions described in this +reference documentation. + + + +[h3 [#filesystem_error-members] `filesystem_error` members +\[filesystem_error.members\]] + + +``` +[#filesystem_error-2-arg]filesystem_error(const std::string& what_arg, error_code ec); +``` + +[: + + +['Postcondition:] + + + +[table + +[ + [[*Expression]] + [[*Value]] + ] + + +[ + [` + runtime_error::what()`] + [ + `['what_arg].c_str()`] + ] + + +[ + [`code()`] + [`ec`] + ] + + +[ + [`path1().empty()`] + [`true`] + ] + + +[ + [`path2().empty()`] + [`true`] + ] + + ] + +] + + + +``` +[#filesystem_error-3-arg]filesystem_error(const std::string& what_arg, const path& p1, error_code ec); +``` + +[: + + +['Postcondition:] + + + +[table + +[ + [[*Expression]] + [[*Value]] + ] + + +[ + [` + runtime_error::what()`] + [ + `['what_arg].c_str()`] + ] + + +[ + [`code()`] + [`ec`] + ] + + +[ + [`path1()`] + [Reference to stored copy of `p1`] + ] + + +[ + [`path2().empty()`] + [`true`] + ] + + ] + +] + + + +``` +[#filesystem_error-4-arg]filesystem_error(const std::string& what_arg, const path& p1, const path& p2, error_code ec); +``` + +[: + + +['Postcondition:] + + + +[table + +[ + [[*Expression]] + [[*Value]] + ] + + +[ + [` + runtime_error::what()`] + [ + [_ + `['w]`]`['hat_arg].c_str()`] + ] + + +[ + [`code()`] + [`ec`] + ] + + +[ + [`path1()`] + [Reference to stored copy of `p1`] + ] + + +[ + [`path2()`] + [Reference to stored copy of `p2`] + ] + + ] + +] + + + +``` +const path& [#filesystem_error-path1]path1() const; +``` + +[: + + +['Returns:] Reference to copy of `p1` stored by the + constructor, or, if none, an empty path. + + +] + + + +``` +const path& [#filesystem_error-path2]path2() const; +``` + +[: + + +['Returns:] Reference to copy of `p2` stored by the + constructor, or, if none, an empty path. + + +] + + + +``` +const char* [#filesystem_error-what]what() const; +``` + +[: + + +['Returns: ]A string containing `runtime_error::what()`. The exact format is unspecified. + Implementations are encouraged but not required to include `path1.native_string()`if not empty, `path2.native_string()`if + not empty, and `system_error::what()` strings in the returned + string. + + +] + + + +[h2 [#Enum-file_type]Enum file_type \[enum.file_type\]] + + + +This enum specifies constants uses to identify file types. + + + +[table + +[ + [[*Constant Name]] + [[*Meaning]] + ] + + +[ + [`status_error`] + [An error occurred while trying to obtain the status of the file. The + file simply not being found is [*[_not]] considered a status error. ] + ] + + +[ + [`file_not_found`] + [The file could not be found] + ] + + +[ + [`regular_file`] + [Regular file] + ] + + +[ + [`directory_file`] + [Directory file] + ] + + +[ + [`symlink_file`] + [Symbolic link file] + ] + + +[ + [`block_file`] + [Block special file] + ] + + +[ + [`character_file`] + [Character special file] + ] + + +[ + [`fifo_file`] + [FIFO or pipe file] + ] + + +[ + [`socket_file`] + [Socket file] + ] + + +[ + [`type_unknown`] + [The file exists, but it is of a system specific type not covered by any + of the above cases.] + ] + +] + + +[h2 [#Enum-perms]Enum perms \[enum.perms\]] + + + +This `enum` specifies bitmask constants uses to identify file +permissions. ['ISO/IEC 9945 +(POSIX) specifies actual values, and those values have been adopted here because +they are very familiar and ingrained for many POSIX +users.] + + +[: + + +Windows: All permissions except write are currently ignored. There is only a +single write permission; setting write permission for owner, group, or others +sets write permission for all, and removing write permission for owner, group, +or others removes write permission for all. + + +] + + + +[table + +[ + [[*Name]] + [[*Value + + (octal)]] + [[*ISO/IEC 9945 + + macro]] + [[*Definition or notes]] + ] + + + +[[ + + +`no_perms` + +][`0`][] + [There are no permissions set for the file. Note: `file_not_found` is `no_perms` rather than `perms_not_known`] +] + + +[[`owner_read`][`0400`][ `S_IRUSR`] + [ Read permission, owner] +] + + +[[`owner_write`][`0200`][ `S_IWUSR`] + [ Write permission, owner] +] + + +[[`owner_exe`][`0100`][ `S_IXUSR`] + [ Execute/search permission, owner] +] + + +[[`owner_all`][`0700`][ `S_IRWXU`] + [ Read, write, execute/search by owner; `owner_read | owner_write | owner_exe`] +] + + +[[`group_read`][`040`][ `S_IRGRP`] + [ Read permission, group] +] + + +[[`group_write`][`020`][ `S_IWGRP`] + [ Write permission, group] +] + + +[[`group_exe`][`010`][ `S_IXGRP`] + [ Execute/search permission, group] +] + + +[[`group_all`][`070`][ `S_IRWXG`] + [ Read, write, execute/search by group; `group_read | group_write | group_exe`] +] + + +[[`others_read`][`04`][ `S_IROTH`] + [ Read permission, others] +] + + +[[`others_write`][`02`][ `S_IWOTH`] + [ Write permission, others] +] + + +[[`others_exe`][`01`][ `S_IXOTH`] + [ Execute/search permission, others] +] + + +[[`others_all`][`07`][ `S_IRWXO`] + [Read, write, execute/search by others; `others_read | others_write | others_exe`] +] + + +[[`all_all`][`0777`][ ][`owner_all | group_all | others_all`] +] + + +[[`set_uid_on_exe`][`04000`][ `S_ISUID`] + [ Set-user-ID on execution] +] + + +[[`set_gid_on_exe`][`02000`][ `S_ISGID`] + [ Set-group-ID on execution] +] + + +[[`[#sticky_bit]sticky_bit `][`01000`][ `S_ISVTX`] + [ Operating system dependent. Inherently non-portable, even between ISO/IEC 9945 + operating systems.] +] + + +[[`[#perms_mask]perms_mask`][`07777`][  ] + [`all_all | set_uid_on_exe | set_gid_on_exe | sticky_bit`] +] + + +[[`perms_not_known`][`0xFFFF`][][ + The permissions are not known, such as when a `file_status` object + is created without specifying the permissions] +] + + +[[ + + +`add_perms` + +][`0x1000`][][ + + +`permissions()` adds the argument permission bits to the + file's current bits + +] +] + + +[[`remove_perms`][`0x2000`][][ + `permissions()` removes the argument permission bits from the + file's current bits] +] + + +[[`[#symlink_perms]symlink_perms`][`0x4000`][][ + On ISO/IEC 9945 + `permissions()` resolves symlinks unless + `symlink_perms` is specified. + Meaningless on Windows as ` + permissions()` never resolves symlinks. + Meaningless on Mac OS X and some other BSD systems as ` + permissions()` always resolves symlinks. Get over it.] +] + + +] + + +[h2 [#file_status]Class file_status \[class.file_status\]] + + +``` +namespace boost +{ + namespace filesystem + { + class file_status + { + public: + + // [@#file_status-constructors constructors] + file_status() noexcept; + explicit file_status([@#file_type file_type] ft, [@#Enum-perms perms] prms = perms_not_known) noexcept; + + // compiler generated + file_status(const file_status&) noexcept; + file_status& operator=(const file_status&) noexcept; + ~file_status() noexcept; + + // [@#file_status-observers observers] + [@#file_type file_type] type() const noexcept; + [@#Enum-perms perms] permissions() const noexcept; + + // [@#file_status-modifiers modifiers] + void type([@#file_type file_type] ft) noexcept; + void permissions([@#Enum-perms perms] prms) noexcept; + }; + } // namespace filesystem +} // namespace boost +``` + + + +An object of type `file_status` stores information about the type +and permissions of a file. + + + +[h3 [#file_status-constructors]`file_status` constructors +\[file_status.cons\]] + + +``` +explicit file_status() noexcept; +``` + +[: + + +['Postconditions:] `type() == status_error`, `permissions() == perms_not_known`. + + +] + + + +``` +explicit file_status([@#file_type file_type] ft, [@#Enum-perms perms] prms = perms_not_known) noexcept; +``` + +[: + + +['Postconditions:] `type() == ft`, `permissions() == prms`. + + +] + + + +[h3 [#file_status-observers]`file_status` observers \[file_status.obs\]] + + +``` +[@#file_type file_type] type() const noexcept; +``` + +[: + + +['Returns: ]The value of `type()` specified by the ['postconditions] of the most recent call to a constructor, operator=, or `type(file_type)` function. + + +] + + + +``` +[@#Enum-perms perms] permissions() const noexcept; +``` + +[: + + +['Returns: ]The value of `permissions()` specified by the ['postconditions] of the most recent call to a constructor, operator=, or `permissions(perms)` function. + + +] + + + +[h3 [#file_status-modifiers]`file_status` modifiers \[file_status.mods\]] + + +``` +void type([@#file_type file_type] ft) noexcept; +``` + +[: + + +['Postconditions:] `type() == ft`. + + +] + + + +``` +void permissions([@#Enum-perms perms] prms) noexcept; +``` + +[: + + +['Postconditions:] `permissions() == prms`. + + +] + + + +[h2 [#Class-directory_entry]Class `directory_entry` \[class.directory_entry\]] + + + +``` +namespace boost +{ + namespace filesystem + { + class directory_entry + { + public: + + // [@#directory_entry-constructors constructors] and destructor + directory_entry(); + directory_entry(const directory_entry&); + explicit directory_entry(const path& p); + directory_entry(const path& p, system::error_code& ec); // v4-only + directory_entry(const path& p, file_status st, // v3-only + file_status symlink_st=file_status()); + ~directory_entry(); + + // [@#directory_entry-modifiers modifiers] + directory_entry& operator=(const directory_entry&); + void assign(const path& p); + void assign(const path& p, system::error_code& ec); // v4-only + void assign(const path& p, file_status st, // v3-only + file_status symlink_st=file_status()); + void replace_filename(const path& p); + void replace_filename(const path& p, system::error_code& ec); // v4-only + void replace_filename(const path& p, file_status st, // v3-only + file_status symlink_st=file_status()); + + void refresh(); + void refresh(system::error_code& ec); + + // [@#directory_entry-observers observers] + const path& path() const; + + file_status status() const; + file_status status(system::error_code& ec) const; + file_status symlink_status() const; + file_status symlink_status(system::error_code& ec) const; + file_type file_type() const; + file_type file_type(system::error_code& ec) const; + file_type symlink_file_type() const; + file_type symlink_file_type(system::error_code& ec) const; + + bool exists() const; + bool exists(system::error_code& ec) const; + bool is_regular_file() const; + bool is_regular_file(system::error_code& ec) const; + bool is_directory() const; + bool is_directory(system::error_code& ec) const; + bool is_symlink() const; + bool is_symlink(system::error_code& ec) const; + bool is_block_file() const; + bool is_block_file(system::error_code& ec) const; + bool is_character_file() const; + bool is_character_file(system::error_code& ec) const; + bool is_fifo() const; + bool is_fifo(system::error_code& ec) const; + bool is_socket() const; + bool is_socket(system::error_code& ec) const; + bool is_reparse_file() const; + bool is_reparse_file(system::error_code& ec) const; + bool is_other() const; + bool is_other(system::error_code& ec) const; + + bool operator< (const directory_entry& rhs); + bool operator==(const directory_entry& rhs); + bool operator!=(const directory_entry& rhs); + bool operator< (const directory_entry& rhs); + bool operator<=(const directory_entry& rhs); + bool operator> (const directory_entry& rhs); + bool operator>=(const directory_entry& rhs); + private: + path m_path; // for exposition only + mutable file_status m_status; // for exposition only; stat()-like + mutable file_status m_symlink_status; // for exposition only; lstat()-like + }; + + } // namespace filesystem +} // namespace boost +``` + + + + +A `directory_entry` object stores a `path` object, +as well as some amount of cached information about the file identified by the path. +Currently, the cached information includes a `file_status` object for non-symbolic +link status and a `file_status` object for symbolic link status. + + +[: + + +\[['Note:] Because `status()` on a pathname may be a relatively expensive operation, +some operating systems provide status information as a byproduct of directory +iteration. Caching such status information can result is significant time savings. Cached and +non-cached results may differ in the presence of file system races. ['—end note]\] + + + + +['Actual cold-boot timing of iteration over +a directory with 15,047 entries was six seconds for non-cached status queries +versus one second for cached status queries. Windows XP, 3.0 GHz processor, with +a moderately fast hard-drive. Similar speedups are expected on Linux and BSD-derived +systems that provide status as a by-product of directory iteration.] + + + + +\[['Note:] The exact set of cached information may vary from one Boost.Filesystem version +to another, and also between different operating systems and underlying file systems. Users' code +must not rely on whether a certain piece of information is cached or not. This means that calling +most observers and modifiers of `directory_entry` may or may not result in a filesystem +query that may potentially fail. Information caching is exclusively a performance feature aimed +at reducing the amount of such queries. ['—end note]\] + + +] + + + +[h3 [#directory_entry-constructors] `directory_entry` constructors +\[directory_entry.cons\]] + + +``` +directory_entry(); +``` + +[: + + +['Postcondition:] + + + +[table + +[ + [[*Expression]] + [[*Value]] + ] + + +[ + [`path().empty()`] + [`true`] + ] + + +[ + [`status()`] + [`file_status()`] + ] + + +[ + [`symlink_status()`] + [`file_status()`] + ] + + ] + +] + + + +``` +explicit directory_entry(const path& p); +directory_entry(const path& p, system::error_code& ec); // v4-only +``` + +[: + + +['Effects:] + + + + +[*v3:] Initializes `m_path` from `p` and default-constructs `m_status` and `m_symlink_status`. + + + + +\[['Note:] The cached file statuses will be updated when queried by the caller or by an explicit call to `refresh`. ['—end note]\] + + + + +[*v4:] Initializes `m_path` from `p` and calls `refresh()` or `refresh(ec)`, respectively. + + + + +['Postcondition:] `path() == p` if no error occurs, otherwise `path().empty() == true`. + + +] + + + +``` +directory_entry(const path& p, file_status st, file_status symlink_st=file_status()); // v3-only +``` + +[: + + +[*v3:] ['Postcondition:] + + + +[table + +[ + [[*Expression]] + [[*Value]] + ] + + +[ + [`path()`] + [`p`] + ] + + +[ + [`status()`] + [`st`] + ] + + +[ + [`symlink_status()`] + [`symlink_st`] + ] + + ] + +] + + + +[h3 [#directory_entry-modifiers] `directory_entry` modifiers +\[directory_entry.mods\]] + + +``` +void assign(const path& p); +void assign(const path& p, system::error_code& ec); // v4-only +``` + +[: + + +['Effects:] + + + + +[*v3:] Assigns `p` to `m_path` and `file_status()` to `m_status` and `m_symlink_status`. + + + + +\[['Note:] The cached file statuses will be updated when queried by the caller or by an explicit call to `refresh`. ['—end note]\] + + + + +[*v4:] Assigns `p` to `m_path` and calls `refresh()` or `refresh(ec)`, respectively. If an error + occurs, the value of the cached data is unspecified. + + +] + + + +``` +void assign(const path& p, file_status st, file_status symlink_st=file_status()); // v3-only +``` + +[: + + +[*v3:] ['Postcondition:] + + + +[table + +[ + [[*Expression]] + [[*Value]] + ] + + +[ + [`path()`] + [`p`] + ] + + +[ + [`status()`] + [`st`] + ] + + +[ + [`symlink_status()`] + [`symlink_st`] + ] + + ] + +] + + + +``` +void replace_filename(const path& p); +void replace_filename(const path& p, system::error_code& ec); // v4-only +``` + +[: + + +['Effects:] + + + + +[*v3:] Calls `m_path.replace_filename(p)` and assigns `file_status()` to `m_status` and `m_symlink_status`. + + + + +\[['Note:] The cached file statuses will be updated when queried by the caller or by an explicit call to `refresh`. ['—end note]\] + + + + +[*v4:] Calls `m_path.replace_filename(p)` and then `refresh()` or `refresh(ec)`, respectively. If an error + occurs, the value of the cached data is unspecified. + + +] + + + +``` +void replace_filename(const path& p, file_status st, file_status symlink_st=file_status()); // v3-only +``` + +[: + + +['Effects:] [*v3:] Calls `m_path.replace_filename(p)` and assigns `st` to `m_status` and `symlink_st` + to `m_symlink_status`. + + +] + + + +``` +void refresh(); +void refresh(system::error_code& ec); +``` + +[: + + +['Effects:] Updates any cached data by querying the filesystem about the file identified by `m_path`. If an error occurs, + the value of the cached data is unspecified. + + +] + + + +[h3 [#directory_entry-observers] `directory_entry` observers +\[directory_entry.obs\]] + + +``` +const path& path() const; +``` + +[: + + +['Returns:] `m_path` + + +] + + + +``` +file_status status() const; +file_status status(system::error_code& ec) const; +``` + +[: + + +['Effects:] If `!status_known(m_status)`, calls `refresh()` or `refresh(ec)`, respectively. + + + + +['Returns:] `m_status` + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + +] + + + +``` +file_status symlink_status() const; +file_status symlink_status(system::error_code& ec) const; +``` + +[: + + +['Effects:] If `!status_known(m_symlink_status)`, calls `refresh()` or `refresh(ec)`, respectively. + + + + +['Returns:] `m_symlink_status` + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + +] + + + +``` +file_type file_type() const; +file_type file_type(system::error_code& ec) const; +``` + +[: + + +['Effects:] Equivalent to `status().type()` or `status(ec).type()`, respectively. + + + + +\[['Note:] The implementation may be more efficient than calling `status`, if the information + about the file type is cached, but permissions are not. ['—end note]\] + + +] + + + +``` +file_type symlink_file_type() const; +file_type symlink_file_type(system::error_code& ec) const; +``` + +[: + + +['Effects:] Equivalent to `symlink_status().type()` or `symlink_status(ec).type()`, respectively. + + + + +\[['Note:] The implementation may be more efficient than calling `symlink_status`, if the information + about the file type is cached, but permissions are not. ['—end note]\] + + +] + + + +``` +bool exists() const; +bool exists(system::error_code& ec) const; +``` + +[: + + +['Effects:] Equivalent to `exists(status())` or `exists(status(ec))`, respectively. + + +] + + + +``` +bool is_regular_file() const; +bool is_regular_file(system::error_code& ec) const; +``` + +[: + + +['Effects:] Equivalent to `is_regular_file(status())` or `is_regular_file(status(ec))`, respectively. + + +] + + + +``` +bool is_directory() const; +bool is_directory(system::error_code& ec) const; +``` + +[: + + +['Effects:] Equivalent to `is_directory(status())` or `is_directory(status(ec))`, respectively. + + +] + + + +``` +bool is_symlink() const; +bool is_symlink(system::error_code& ec) const; +``` + +[: + + +['Effects:] Equivalent to `is_symlink(symlink_status())` or `is_symlink(symlink_status(ec))`, respectively. + + +] + + + +``` +bool is_block_file() const; +bool is_block_file(system::error_code& ec) const; +``` + +[: + + +['Effects:] Equivalent to `is_block_file(status())` or `is_block_file(status(ec))`, respectively. + + +] + + + +``` +bool is_character_file() const; +bool is_character_file(system::error_code& ec) const; +``` + +[: + + +['Effects:] Equivalent to `is_character_file(status())` or `is_character_file(status(ec))`, respectively. + + +] + + + +``` +bool is_fifo() const; +bool is_fifo(system::error_code& ec) const; +``` + +[: + + +['Effects:] Equivalent to `is_fifo(status())` or `is_fifo(status(ec))`, respectively. + + +] + + + +``` +bool is_socket() const; +bool is_socket(system::error_code& ec) const; +``` + +[: + + +['Effects:] Equivalent to `is_socket(status())` or `is_socket(status(ec))`, respectively. + + +] + + + +``` +bool is_reparse_file() const; +bool is_reparse_file(system::error_code& ec) const; +``` + +[: + + +['Effects:] Equivalent to `is_reparse_file(symlink_status())` or `is_reparse_file(symlink_status(ec))`, respectively. + + +] + + + +``` +bool is_other() const; +bool is_other(system::error_code& ec) const; +``` + +[: + + +['Effects:] Equivalent to `is_other(status())` or `is_other(status(ec))`, respectively. + + +] + + + +``` +bool operator==(const directory_entry& rhs); +``` + +[: + + +['Returns:] `m_path == rhs.m_path`. + + +] + + + +``` +bool operator!=(const directory_entry& rhs); +``` + +[: + + +['Returns:] `m_path != rhs.m_path`. + + +] + + + +``` +bool operator< (const directory_entry& rhs); +``` + +[: + + +['Returns:] `m_path < rhs.m_path`. + + +] + + + +``` +bool operator<=(const directory_entry& rhs); +``` + +[: + + +['Returns:] `m_path <= rhs.m_path`. + + +] + + + +``` +bool operator> (const directory_entry& rhs); +``` + +[: + + +['Returns:] `m_path > rhs.m_path`. + + +] + + + +``` +bool operator>=(const directory_entry& rhs); +``` + +[: + + +['Returns:] `m_path >= rhs.m_path`. + + +] + + + +[h2 [#Class-directory_iterator]Class `directory_iterator` +\[class.directory_iterator\]] + + + +Objects of type `directory_iterator` provide standard library +compliant iteration over the contents of a directory. Also see class `[@#Class-recursive_directory_iterator recursive_directory_iterator]`. + + + +``` +namespace boost +{ + namespace filesystem + { + class directory_iterator + { + public: + // [@#directory_iterator-members member functions] + + directory_iterator() noexcept; // creates the "end" iterator + directory_iterator(const directory_iterator&); + explicit directory_iterator(const path& p, [@#directory_options directory_options] opts = directory_options::none); + directory_iterator(const path& p, system::error_code& ec); + directory_iterator(const path& p, [@#directory_options directory_options] opts, system::error_code& ec); + ~directory_iterator(); + + directory_iterator& operator=(const directory_iterator&); + + directory_iterator& operator++(); + directory_iterator& increment(system::error_code& ec); + + // other members as required by + // C++ Std, 24.1.1 Input iterators \[input.iterators\] + }; + + } // namespace filesystem +} // namespace boost +``` + + + + `directory_iterator` satisfies the requirements of an +input iterator (C++ Std, 24.2.1, Input iterators \[input.iterators\]). + + + + +A `directory_iterator` reads successive elements from the directory for +which it was constructed, as if by calling ISO/IEC 9945 `[@http://www.opengroup.org/onlinepubs/000095399/functions/readdir_r.html readdir() or readdir_r()]`. After a `directory_iterator` is constructed, and every time `operator++` is called, +it reads a directory element and stores information about it in an object of type `[@#Class-directory_entry directory_entry]`. `operator++` is not equality preserving; that is, `i == j` does not imply that `++i == ++j`. + + +[: + + +\[['Note:] The practical consequence of not preserving equality is that directory iterators +can only be used for single-pass algorithms. ['—end note]\] + + +] + + + + +If the end of the directory elements is reached, the iterator shall become equal to +the end iterator value. The constructor `directory_iterator()` with no arguments always constructs an end iterator object, which +shall be the only valid iterator for the end condition. The result of `operator*` on an end iterator is not defined. For any other iterator value +a `const directory_entry&` is returned. The result of `operator->` on an end iterator is +undefined behavior. For any other iterator value a `const directory_entry*` is +returned. + + + + +Two end iterators are always equal. An end iterator shall not be equal to a non-end +iterator. + + +[: + + +['The above wording is based on the +Standard Library's istream_iterator wording.] + + +] + + + + +The result of calling the `path()` member of the `directory_entry` object obtained by dereferencing a `directory_iterator` is a reference to a `path` object composed of the directory argument from which the iterator was +constructed with filename of the directory entry appended as if by `operator/=`. + + + + +Directory iteration shall not yield directory entries for the current (['dot]) +and parent (['dot dot]) directories. + + + + +The order of directory entries obtained by dereferencing successive +increments of a `directory_iterator` is unspecified. + + +[: + + +\[['Note:] Programs performing directory iteration may wish to test if the +path obtained by dereferencing a directory iterator actually exists. It could be +a +symbolic link to a non-existent file. Programs recursively +walking directory trees for purposes of removing and renaming entries may wish +to avoid following symbolic links. + + + + +If a file is removed from or added to a directory after the +construction of a `directory_iterator` for the directory, it is +unspecified whether or not subsequent incrementing of the iterator will ever +result in an iterator whose value is the removed or added directory entry. See +ISO/IEC 9945 `[@http://www.opengroup.org/onlinepubs/000095399/functions/readdir_r.html readdir_r()]`. ['—end note]\] + + +] + + + +[h3 [#directory_iterator-members]`directory_iterator` members +\[directory_iterator.members\]] + + + + +`[#directory_iterator-default-ctor]directory_iterator() +noexcept;` + + + +[: + + + +['Effects:] Constructs the end iterator. + + + +] + + + + +``` +explicit [#directory_iterator-ctor-path]directory_iterator(const path& p, [@#directory_options directory_options] opts = directory_options::none); +directory_iterator(const path& p, system::error_code& ec); +directory_iterator(const path& p, [@#directory_options directory_options] opts, system::error_code& ec); +``` + +[: + + + +['Effects:] Constructs an iterator representing the first +entry in the directory `p` resolves to, if any; otherwise, the end iterator. +If opening the directory fails with a `permission_denied` error and `(opts & directory_options::skip_permission_denied) != 0`, +constructs the end iterator and ignores the error (the operation completes successfully). If `opts` is not specified, it is assumed to be `directory_options::none`. + + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + + + + +\[['Note:] To iterate over the current directory, use `directory_iterator(".")` rather than `directory_iterator("")`. ['—end note]\] + + +] + + + +``` +directory_iterator& [#directory_iterator-increment]operator++(); +directory_iterator& increment(system::error_code& ec); +``` + +[: + + + +['Effects:] As specified by the C++ Standard, 24.1.1 Input iterators \[input.iterators\]. In case of error the iterator is left in the end state. + + + + + +['Returns:] `*this`. + + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + + +] + + + +[h3 [#directory_iterator-non-member-functions]`directory_iterator` non-member functions] + + +``` +const directory_iterator& begin(const directory_iterator& iter); +``` + +[: + + +['Returns: ]`iter`. + + +] + + + +``` +directory_iterator end(const directory_iterator&); +``` + +[: + + +['Returns: ]`directory_iterator()`. + + +] + + + +[h2 [#Class-recursive_directory_iterator]Class `recursive_directory_iterator` +\[class.rec.dir.itr\]] + + + +Objects of type `recursive_directory_iterator` provide standard library +compliant iteration over the contents of a directory, including recursion into +its sub-directories. + + + +``` +namespace boost +{ + namespace filesystem + { + class recursive_directory_iterator : + public iterator + { + public: + + // constructors and destructor + recursive_directory_iterator() noexcept; + recursive_directory_iterator(const recursive_directory_iterator&); + explicit recursive_directory_iterator(const path& p, + [@#directory_options directory_options] opts = directory_options::none); + recursive_directory_iterator(const path& p, + [@#directory_options directory_options] opts, system::error_code& ec); + recursive_directory_iterator(const path& p, system::error_code& ec); + ~recursive_directory_iterator(); + + // observers + int depth() const noexcept; + bool recursion_pending() const noexcept; + + // modifiers + recursive_directory_iterator& operator=(const recursive_directory_iterator&); + + recursive_directory_iterator& operator++(); + recursive_directory_iterator& increment(system::error_code& ec); + + void pop(); + void pop(system::error_code& ec); + void disable_recursion_pending(bool value = true) noexcept; + + // other members as required by + // C++ Std, Input iterators \[input.iterators\] + + private: +['[* // actual data members will probably be stored in a shared object, + // or some similar mechanism, to achieve the required input iterator + // copy semantics]] + int m_depth; [*['// for exposition only]] + bool m_recursion_pending; ['[*// for exposition only]] + [@#directory_options directory_options] m_options; ['[*// for exposition only]] + }; + + } // namespace filesystem +} // namespace boost +``` + + + + +The behavior of a `recursive_directory_iterator` is the same +as a `directory_iterator` unless otherwise specified. + + + + * Incrementing a `recursive_directory_iterator` pointing to a + directory causes that directory itself to be iterated over, as specified by + the `operator++` and `increment` functions. + +  + * When a `recursive_directory_iterator` reaches the end of the directory currently being iterated + over, or when `pop()` is called, `m_depth` is + decremented, and iteration of the parent directory continues. + + +``` +recursive_directory_iterator() noexcept; +``` + +[: + + + +['Effects:] Constructs the end iterator. + + + +] + + + + +``` +explicit recursive_directory_iterator(const path& p, [@#directory_options directory_options] opts = directory_options::none); +recursive_directory_iterator(const path& p, [@#directory_options directory_options] opts, system::error_code& ec); +recursive_directory_iterator(const path& p, system::error_code& ec); +``` + +[: + + + +['Effects:]  Constructs an iterator representing the first +entry in the directory `p` resolves to, if any; otherwise, the end iterator. + + + + + +['Postcondition: ]Unless the end iterator was constructed,[' ]`depth() == 0 && recursion_pending() == true && m_options == opts`. +For the signature without the `opts` argument, `opts` is assumed to be `directory_options::none`. + + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + + + + +\[['Note:] To iterate over the current directory, use `recursive_directory_iterator(".")` rather than `recursive_directory_iterator("")`. ['—end note]\] + + + + + +\[['Note:] By default, `recursive_directory_iterator` does not +follow directory symlinks. To follow directory symlinks, specify `directory_options::follow_directory_symlink` in `opts`. ['—end note]\] + + +] + + + +``` +int depth() const noexcept; +``` + +[: + + +['Requires:] `*this != recursive_directory_iterator()`. + + + + +['Returns:] `m_depth`. + + +] + + + +``` +bool recursion_pending() const noexcept; +``` + +[: + + +['Requires:] `*this != recursive_directory_iterator()`. + + + + +['Returns:] `m_recursion_pending`. + + +] + + + +``` +recursive_directory_iterator& [#recursive_directory_iterator-increment]operator++(); +recursive_directory_iterator& increment(system::error_code& ec); +``` + +[: + + + +['Effects:] As specified by the C++ Standard, 24.1.1 Input iterators \[input.iterators\], +except: + + + + + * + + + +if `recursion_pending() && is_directory(this->status()) +&& (!is_symlink(this->symlink_status()) || (m_options & directory_options::follow_directory_symlink) != 0)` then: + + + + * + + +directory `(*this)->path()` is opened and recursively iterated into and `m_depth` is incremented; + + + + * + + +if opening the directory fails with a `permission_denied` error and `(m_options & directory_options::skip_permission_denied) != 0`, + increment the iterator on the current level and ignore the error (the operation completes successfully). + + + + + + + + * if there are no more directory entries at this level then `m_depth` +is decremented and iteration of the parent directory resumes. + + + + +If the operation completes with an error, then + + + + * if `(m_options & directory_options::pop_on_error) != 0`, the iterator is left in a state as if after repeatedly calling `pop()` until it succeeds or the iterator becomes equal to an end iterator; any `pop()` failures are not reported to the caller; + * otherwise, the iterator is left equal to an end iterator. + + + + + +['Postcondition:] `recursion_pending() == true`. + + + + + +['Returns:] `*this`. + + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + + +] + + + +``` +void pop(); +void pop(system::error_code& ec); +``` + +[: + + +['Requires:] `*this != recursive_directory_iterator()`. + + + + +['Effects:] If `depth() == 0`, set `*this` to `recursive_directory_iterator()`. + Otherwise, `--m_depth`, cease iteration of the directory currently being + iterated over, and continue iteration over the parent directory. + + + + +If the operation completes with an error, then + + + + * if `(m_options & directory_options::pop_on_error) != 0`, the iterator is left in a state as if after repeatedly calling `pop()` until it succeeds or the iterator becomes equal to an end iterator; any `pop()` failures are not reported to the caller; + * otherwise, the iterator is left equal to an end iterator. + + +] + + + +``` +void disable_recursion_pending(bool value = true) noexcept; +``` + +[: + + +['Requires:] `*this != recursive_directory_iterator()`. + + + + +['Postcondition:] `recursion_pending() == !value`. + + + + +\[['Note:] These functions are used to prevent + unwanted recursion into a directory. ['—end note]\] + + +] + + + +[h3 [#recursive_directory_iterator-non-member-functions]`recursive_directory_iterator` non-member functions] + + +``` +const recursive_directory_iterator& begin(const recursive_directory_iterator& iter); +``` + +[: + + +['Returns: ]`iter`. + + +] + + + +``` +recursive_directory_iterator end(const recursive_directory_iterator&); +``` + +[: + + +['Returns: ]`recursive_directory_iterator()`. + + +] + + + +[h2 [#Operational-functions]Operational functions \[fs.op.funcs\]] + + + +Operational functions query or modify files, including directories, in external +storage. + + + + +Operational functions access a file by resolving an +object of class `path` to a particular file in a file hierarchy. The +path is resolved as if by the ISO/IEC 9945 [@http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap04.html#tag_04_11 Pathname Resolution] mechanism. + + + + +\[['Note: ]Because hardware failures, network failures, [@#file-system-race file system races], and many +other kinds of errors occur frequently in file system operations, users should be aware +that any filesystem operational function, no matter how apparently innocuous, may encounter +an error. See [@#Error-reporting Error reporting]. ['—end note]\] + + + +``` +path [#absolute]absolute(const path& p, const path& base=current_path()); +path absolute(const path& p, system::error_code& ec); +path absolute(const path& p, const path& base, system::error_code& ec); +``` + + [: + + +['Returns:] If `p.is_absolute()` is `true` then `p`, otherwise an [@#Absolute-path absolute path] composed according to the + following table: + + + +[table + +[ + [ ] + [[*`p. + + has_root_directory()`]] + [[*`!p.has_root_directory()`]] + ] + + +[ + [[*`p.has_root_name()`]] + [`return p`] + [`return + + p.root_name() + + / absolute(base) + +    .root_directory() + +  / absolute(base) + +    .relative_path() + + / p.relative_path()`] + ] + + +[ + [[*`!p.has_root_name()`]] + [`return + + absolute(base) + +  .root_name() + +  / p`] + [`return absolute(base) + + / p`] + ] + + ] + + + +For the overload without a `base` argument, `base` is `current_path()`. + + + + +\[['Note:] For the returned path, `rp`, `rp.is_absolute()` is `true`. ['—end note]\] + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + +] + + + +``` +path [#canonical]canonical(const path& p, const path& base = current_path()); +path canonical(const path& p, system::error_code& ec); +path canonical(const path& p, const path& base, system::error_code& ec); +``` + +[: + + +['Overview:] Converts `p` to an absolute +path that has no symbolic link, [@#Dot dot], +or [@#Dot dot-dot] elements. Testing path elements for symbolic links +is done as if by calling `[@#is_symlink2 is_symlink]` and requires +`[@#absolute absolute](p, base)` to exist. + + + + +['Returns:] A [@#canonical-path canonical path] that refers to +the same file system object as `[@#absolute absolute](p, base)`. For the overload +without a `base` argument, `base` is `[@#current_path current_path]()`. + + + + +['Throws:]  As specified in [@#Error-reporting Error reporting]. + + + + + +['Remarks:] `!exists(absolute(p, base))` is an error. + + + + + +\[['Note:] Canonical pathnames allow security checking of a path (e.g. + does this path live in /home/goodguy or /home/badguy?) ['—end note]\] + + + +] + + + +``` +void copy(const path& from, const path& to); +void copy(const path& from, const path& to, system::error_code& ec); +``` + +[: + + +['Effects: ]`copy(from, to, copy_options::none`['\[]`, ec`['\]]`)`. + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + +] + + + +``` +void [#copy]copy(const path& from, const path& to, [@#copy_options copy_options] options); +void copy(const path& from, const path& to, [@#copy_options copy_options] options, system::error_code& ec); +``` + +[: + + +['Precondition:] `options` must contain at most one option from each of the following groups: + + + + * `copy_options::skip_existing`, `copy_options::overwrite_existing` or `copy_options::update_existing`; + * `copy_options::synchronize_data` or `copy_options::synchronize`; + * `copy_options::ignore_attribute_errors`; + * `copy_options::recursive`; + * `copy_options::copy_symlinks` or `copy_options::skip_symlinks`; + * `copy_options::directories_only`, `copy_options::create_symlinks` or `copy_options::create_hard_links`. + + + +['Effects:] Let `f` and `t` be `file_status` objects obtained the following way: + + + + * If `(options & (copy_options::create_symlinks | copy_options::skip_symlinks)) != copy_options::none` then `f = [@#symlink_status symlink_status](from)` and `t = [@#symlink_status symlink_status](to)`; + * Otherwise, if `(options & copy_options::copy_symlinks) != copy_options::none` then `f = [@#symlink_status symlink_status](from)` and `t = [@#status status](to)`; + * Otherwise, `f = [@#status status](from)` and `t = [@#status status](to)`. + + Then, report an error if: + + * `!exists(f)`, or + * `equivalent(from, to)`, or + * `is_other(f) || is_other(t)`, or + * `is_directory(f) && is_regular_file(t)`. + + Otherwise, if `is_symlink(f)`, then: + + * If `(options & copy_options::skip_symlinks) != copy_options::none` then return; + * Otherwise if `!exists(t) && (options & copy_options::copy_symlinks) != copy_options::none` then `[@#copy_symlink copy_symlink](from, to)`; + * Otherwise report error. + + Otherwise, if `is_regular_file(f)`, then: + + * If `(options & copy_options::directories_only) != copy_options::none` then return; + * Otherwise if `(options & copy_options::create_symlinks) != copy_options::none` then `[@#create_symlink create_symlink](link, to)`, where `link` is determined as follows: + + * If `from.is_absolute()` then `link` equals to `from`; + * Otherwise, `link` is equivalent to `[@#relative relative]([@#absolute absolute](to.parent_path()), [@#absolute absolute](from.parent_path())) / from.filename()`. + + + * Otherwise if `(options & copy_options::create_hard_links) != copy_options::none` then `[@#create_hard_link create_hard_link](from, to)`; + * Otherwise if `is_directory(t)` then `[@#copy_file copy_file](from, to / from.filename(), options)`; + * Otherwise `[@#copy_file copy_file](from, to, options)`. + + Otherwise, if `is_directory(f)`, then: + + * If `(options & copy_options::create_symlinks) != copy_options::none` then report error with error code equal to `make_error_code(system::errc::is_a_directory)`; + * Otherwise if + + * `(options & copy_options::recursive) != copy_options::none`, or + * `options == copy_options::none` and this call to `copy` is not a recursive call from `copy` + + then: + + * If `!exists(t)`, then `[@#create_directory create_directory](to, from)`. + * Then, iterate over files in `from` and for each `directory_entry x` obtained during iteration invoke `copy(x.path(), to / x.path().filename(), options)`. + + + * Otherwise, return. + + Otherwise, for all unsupported file types of `f` report error. + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + +] + + + + +``` +bool copy_file(const path& from, const path& to); +bool copy_file(const path& from, const path& to, system::error_code& ec); +``` + +[: + + +['Effects: ]`return copy_file(from, to, copy_options::none`['\[]`, ec`['\]]`)`. + + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + + +] + + + +``` +bool [#copy_file]copy_file(const path& from, const path& to, [@#copy_options copy_options] options); +bool copy_file(const path& from, const path& to, [@#copy_options copy_options] options, system::error_code& ec); +``` + +[: + + +['Precondition:] `options` must contain at most one option from each of the following groups: + + + + * `copy_options::skip_existing`, `copy_options::overwrite_existing` or `copy_options::update_existing`; + * `copy_options::synchronize_data` or `copy_options::synchronize`; + * `copy_options::ignore_attribute_errors`. + + + + +['Effects:] Report an error if: + + + + * `!is_regular_file(from)`, or + * `exists(to) && !is_regular_file(to)`, or + * `exists(to) && equivalent(from, to)`, or + * `exists(to) && (options & (copy_options::skip_existing | copy_options::overwrite_existing)) == copy_options::none`. + + Otherwise, return successfully with no effect if: + + * `exists(to) && (options & copy_options::skip_existing) != copy_options::none`, or + * `exists(to) && (options & copy_options::update_existing) != copy_options::none` and last write time of `to` is more recent than that of `from`. + + Otherwise: + + * The contents and attributes of the file `from` resolves to are copied to the file `to` resolves to. If copying file attributes (but not contents) fails with an error and `(options & copy_options::ignore_attribute_errors) != copy_options::none` then that error is ignored. After that, + * If `(options & copy_options::synchronize) != copy_options::none`, the written data and attributes are synchronized with the permanent storage; otherwise + * If `(options & copy_options::synchronize_data) != copy_options::none`, the written data is synchronized with the permanent storage. + + + + +['Returns:] `true` if the file was copied without error, otherwise `false`. + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + + + +\[['Note:] When `copy_options::update_existing` is specified, checking the write times of `from` and `to` may not be atomic with the copy operation. Another process may create or modify the file identified by `to` after the file modification times have been checked but before copying starts. In this case the target file will be overwritten.\] + + + + +\[['Note:] The `copy_options::synchronize_data` and `copy_options::synchronize` options may have a significant performance impact. The `copy_options::synchronize_data` option may be less expensive than `copy_options::synchronize`. However, without these options, upon returning from `copy_file` it is not guaranteed that the copied file is completely written and preserved in case of a system failure. Any delayed write operations may fail after the function returns, at the point of physically writing the data to the underlying media, and this error will not be reported to the caller.\] + + + + +\[['Note:] The `copy_options::ignore_attribute_errors` option can be used when the caller does not require file attributes to be copied. The implementation is permitted to make an attempt to copy the file attributes, but still succeed the file copying operation if that attempt fails. This option may be useful with file systems that do not fully support operations of file attributes.\] + + +] + + + +``` +void [#copy_symlink]copy_symlink(const path& existing_symlink, const path& new_symlink); +void copy_symlink(const path& existing_symlink, const path& new_symlink, system::error_code& ec); +``` + +[: + + +['Effects: ]`create_symlink(read_symlink(existing_symlink`['\[]`, ec`['\]]`), new_symlink`['\[]`, ec`['\]]`)`. + + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + + +] + + + +``` +bool [#create_directories]create_directories(const path& p); +bool [#create_directories2]create_directories(const path& p, system::error_code& ec); +``` + +[: + + +['Effects:] Establishes the postcondition by calling ` + create_directory()` for any element of `p` that does not + exist. + + + + +['Postcondition:] `is_directory(p)` + + + + +['Returns:] `true` if a new directory was created, otherwise ` + false`. + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + + + +['Complexity:] ['O(n+1)] where ['n] is the number of elements + of `p` that do not exist. + + +] + + + +``` +bool [#create_directory]create_directory(const path& p); +bool create_directory(const path& p, system::error_code& ec); +bool create_directory(const path& p, const path& existing); +bool create_directory(const path& p, const path& existing, system::error_code& ec); +``` + +[: + + +['Effects:] Establishes the postcondition by attempting to create the + directory `p` resolves to, as if by ISO/IEC 9945 `[@http://www.opengroup.org/onlinepubs/000095399/functions/mkdir.html + mkdir()]`. For overloads without `existing` argument, the new directory is created with `S_IRWXU|S_IRWXG|S_IRWXO` mode. + Overloads with `existing` argument obtain mode from `existing`, which must be a path to an existing directory. On Windows, + `CreateDirectoryW(p.c_str(), NULL)` is used when `existing` is not specified and `CreateDirectoryExW(existing.c_str(), p.c_str(), NULL)` otherwise. + Creation failure because `p` resolves to an existing directory shall not be + treated as an error. + + + + +['Postcondition:] `is_directory(p)` + + + + +['Returns:] `true` if a new directory was created, otherwise `false`. + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + +] + + + +``` +void [#create_directory_symlink]create_directory_symlink(const path& to, const path& new_symlink); +void create_directory_symlink(const path& to, const path& new_symlink, system::error_code& ec); +``` + +[: + + +['Effects:] Establishes the postcondition, as if by ISO/IEC 9945 `[@http://www.opengroup.org/onlinepubs/000095399/functions/symlink.html symlink()]`. + + + + +[' + Postcondition:] `new_symlink` resolves to a symbolic link file that + contains an unspecified representation of `to`. + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + + + +\[['Note:] Some operating systems, such as Windows, require symlink creation to + identify that the link is to a directory. Portable code should use `create_directory_symlink()` to create directory symlinks rather than `create_symlink()` ['—end note]\] + + + + +\[['Note:] Some operating systems do not support symbolic links at all or support + them only for regular files. + Some file systems do not + support + symbolic links regardless of the operating system - the FAT file system used on + memory cards and flash drives, for example. ['—end note]\] + + + ] + + + +``` +void [#create_hard_link]create_hard_link(const path& to, const path& new_hard_link); +void [#create_hard_link2]create_hard_link(const path& to, const path& new_hard_link, system::error_code& ec); +``` + +[: + + +['Effects:] Establishes the postcondition, as if by ISO/IEC 9945 `[@http://www.opengroup.org/onlinepubs/000095399/functions/link.html link()]`. + + + + +['Postcondition:] + + + + *  `exists(to) && + exists(``new_hard_link``) && equivalent(to, + + ``new_hard_link``)` + * The contents of the file or directory + `to` resolves to are unchanged. + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + + + +\[['Note:] Some operating systems do not support hard links at all or support + them only for regular files. Some file systems do not support hard + links regardless of the operating system - the FAT file system used on memory + cards and flash drives, for example. Some file systems limit the number of + links per file. ['—end note]\] + + + ] + + + +``` +void [#create_symlink]create_symlink(const path& to, const path& new_symlink); +void [#create_symlink2]create_symlink(const path& to, const path& new_symlink, system::error_code& ec); +``` + +[: + + +['Effects:] Establishes the postcondition, as if by ISO/IEC 9945 `[@http://www.opengroup.org/onlinepubs/000095399/functions/symlink.html symlink()]`. + + + + +[' + Postcondition:] `new_symlink` resolves to a symbolic link file that + contains an unspecified representation of `to`. + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + + + +\[['Note:] Some operating systems do not support symbolic links at all or support + them only for regular files. + Some file systems do not + support + symbolic links regardless of the operating system - the FAT system used on + memory cards and flash drives, for example. ['—end note]\] + + + ] + + + +``` +path [#current_path]current_path(); +path [#current_path2]current_path(system::error_code& ec); +``` + +[: + + +['Returns:] The current working directory path, as if by ISO/IEC + 9945 `[@http://www.opengroup.org/onlinepubs/000095399/functions/getcwd.html getcwd()]`. `is_absolute()` is true for the returned path. + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + + + +\[['Note: ]The `current_path()` name was chosen to emphasize that the return is a + path, not just a single directory name. + + + + +The current path as returned by many operating systems is a dangerous + global variable. It may be changed unexpectedly by a third-party or system + library functions, or by another thread.  ['—end note]\] + + +] + + + +``` +void current_path(const path& p); +void current_path(const path& p, system::error_code& ec); +``` + +[: + + +['Effects:] Establishes the postcondition, as if by ISO/IEC 9945 `[@http://www.opengroup.org/onlinepubs/000095399/functions/chdir.html chdir()]`. + + + + +['Postcondition:] `equivalent(p, current_path())`. + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + + + +\[['Note: ]The current path for many operating systems is a dangerous + global state. It may be changed unexpectedly by a third-party or system + library functions, or by another thread.  ['—end note]\] + + +] + + + +``` +bool [#exists]exists(file_status s) noexcept; +``` + +[: + + +['Returns:] `status_known(s) && s.type() != file_not_found` + + +] + + + +``` +bool [#exists2]exists(const path& p); +bool [#exists3]exists(const path& p, system::error_code& ec) noexcept; +``` + +[: + + +['Returns:] `exists(status(p))` or `exists(status(p, ec))`, + respectively. + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + +] + + + +``` +bool [#equivalent]equivalent(const path& p1, const path& p2); +bool [#equivalent2]equivalent(const path& p1, const path& p2, system::error_code& ec); +``` + +[: + + +['Returns:] `true`, if `p1` and `p2` resolve to the same file + system entity, else `false`. + + + [: + + +Two paths are considered to resolve to the same + file system entity if two candidate entities reside on the same device at the + same location. This is determined as if by the values of the ISO/IEC 9945 `[@http://www.opengroup.org/onlinepubs/000095399/basedefs/sys/stat.h.html stat]` structure`,` obtained as if by `[@http://www.opengroup.org/onlinepubs/000095399/functions/stat.html stat()]` for the two paths, having equal `st_dev` values and equal `st_ino` values. + + + + +\[['Note:] ISO/IEC 9945 requires that "['st_dev] must be unique within a Local Area Network". Conservative + ISO/IEC 9945 implementations may also wish to check for equal `st_size` and `st_mtime` values. ['Windows] implementations may use `GetFileInformationByHandle()` as a surrogate for `stat()`, + and consider "same" to be equal values for `dwVolumeSerialNumber`, `nFileIndexHigh`, `nFileIndexLow`, `nFileSizeHigh`, `nFileSizeLow`, `ftLastWriteTime.dwLowDateTime`, and `ftLastWriteTime.dwHighDateTime`. ['—end note]\] + + + ] + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. \[[*v3:] `!exists(p1) && !exists(p2)` is an error. If only one of the paths doesn't exist, `false` is returned without error.\] \[[*v4:] `!exists(p1) || !exists(p2)` is an error.\] + + +] + + + + +``` +uintmax_t [#file_size]file_size(const path& p); +uintmax_t [#file_size2]file_size(const path& p, system::error_code& ec); +``` + + +[: + + +['Returns:] If `exists(p) && is_regular_file(p)`, the size + in bytes + of the file `p` resolves to, determined as if by the value of + the ISO/IEC 9945 `[@http://www.opengroup.org/onlinepubs/000095399/basedefs/sys/stat.h.html stat]` structure member `st_size` obtained as if by + ISO/IEC 9945 `[@http://www.opengroup.org/onlinepubs/000095399/functions/stat.html stat()]`. + Otherwise, `static_cast(-1)`. + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + +] + + + +``` +uintmax_t [#hard_link_count]hard_link_count(const path& p); +uintmax_t hard_link_count(const path& p, system::error_code& ec); +``` + +[: + + + +['Returns:] The number of hard links for `p`. + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + + +] + + + + +``` +const path& [#initial_path]initial_path(); +const path& [#initial_path2]initial_path(system::error_code& ec); +``` + +[: + + +['Returns:] `current_path()` as of the first call to `initial_path()`. + + + + +\[['Note:] `initial_path()` is not thread safe, and may return an undesirable result + if called subsequent to a change to the current directory. These problems can + be avoided by calling `initial_path()` immediately on entry to + main().  ['—end note]\] + + + + +['Throws:] For the first call, as specified in [@#Error-reporting Error reporting]. Subsequent calls throw nothing. + + +] + + + +``` +bool [#is_block_file]is_block_file(file_status s) noexcept; +``` + +[: + + +['Returns:] `s.type() == block_file` + + +] + + + +``` +bool [#is_block_file2]is_block_file(const path& p); +bool [#is_block_file3]is_block_file(const path& p, system::error_code& ec) noexcept; +``` + +[: + + +['Returns:] `is_block_file(status(p))` or `is_block_file(status(p, ec))`, + respectively. The overload with argument `ec` returns `false` if an error occurs. + + + + +['Throws:] `filesystem_error`; the overload with argument `ec` throws +nothing. + + +] + + + +``` +bool [#is_character_file]is_character_file(file_status s) noexcept; +``` + +[: + + +['Returns:] `s.type() == character_file` + + +] + + + +``` +bool [#is_character_file2]is_character_file(const path& p); +bool [#is_character_file3]is_character_file(const path& p, system::error_code& ec) noexcept; +``` + +[: + + +['Returns:] `is_character_file(status(p))` or `is_character_file(status(p, ec))`, + respectively. The overload with argument `ec` returns `false` if an error occurs. + + + + +['Throws:] `filesystem_error`; the overload with argument `ec` throws +nothing. + + +] + + + +``` +bool [#is_directory]is_directory(file_status s) noexcept; +``` + +[: + + +['Returns:] `s.type() == directory_file` + + +] + + + +``` +bool [#is_directory2]is_directory(const path& p); +bool [#is_directory3]is_directory(const path& p, system::error_code& ec) noexcept; +``` + +[: + + +['Returns:] `is_directory(status(p))` or `is_directory(status(p, ec))`, + respectively. The overload with argument `ec` returns `false` if an error occurs. + + + + +['Throws:] `filesystem_error`; the overload with argument `ec` throws +nothing. + + +] + + + +``` +bool [#is_empty]is_empty(const path& p); +bool [#is_empty2]is_empty(const path& p, system::error_code& ec); +``` + +[: + + +['Effects:] Determines `file_status s`, as if by `status(p, ec)`. + + + + +['Returns:] `is_directory(s) + +         ? directory_iterator(p) == directory_iterator() + +         : file_size(p) == 0;` + + +] + + + +``` +bool [#is_fifo]is_fifo(file_status s) noexcept; +``` + +[: + + +['Returns:] `s.type() == fifo_file` + + +] + + + +``` +bool [#is_fifo2]is_fifo(const path& p); +bool [#is_fifo3]is_fifo(const path& p, system::error_code& ec) noexcept; +``` + +[: + + +['Returns:] `is_fifo(status(p))` or `is_fifo(status(p, ec))`, + respectively. The overload with argument `ec` returns `false` if an error occurs. + + + + +['Throws:] `filesystem_error`; the overload with argument `ec` throws +nothing. + + +] + + + +``` +bool [#is_other]is_other(file_status s) noexcept; +``` + +[: + + +['Returns:] `return exists(s) && !is_regular_file(s) && !is_directory(s) && !is_symlink(s)` + + +] + + + +``` +bool [#is_other2]is_other(const path& p); +bool [#is_other3]is_other(const path& p, system::error_code& ec) noexcept; +``` + +[: + + +['Returns:] `is_other(status(p))` or `is_other(status(p, ec))`, + respectively. The overload with argument `ec` returns `false` if an error occurs. + + + + +['Throws:] `filesystem_error`; the overload with argument `ec` throws + nothing. + + +] + + + +``` +bool [#is_regular_file]is_regular_file(file_status s) noexcept; +``` + +[: + + +['Returns:] `s.type() == regular_file` + + +] + + + +``` +bool [#is_regular_file2]is_regular_file(const path& p); +bool [#is_regular_file3]is_regular_file(const path& p, system::error_code& ec) noexcept; +``` + +[: + + +['Returns:] `is_regular_file(status(p))` or `is_regular_file(status(p, ec))`, + respectively. The overload with argument `ec` returns `false` if an error occurs. + + + + +['Throws:] `filesystem_error`; the overload with argument `ec` throws + nothing. + + +] + + + +``` +bool [#is_reparse_file]is_reparse_file(file_status s) noexcept; +``` + +[: + + +['Returns:] `s.type() == reparse_file` + + +] + + + +``` +bool [#is_reparse_file2]is_reparse_file(const path& p); +bool [#is_reparse_file3]is_reparse_file(const path& p, system::error_code& ec) noexcept; +``` + +[: + + +['Returns:] `is_reparse_file(symlink_status(p))` or `is_reparse_file(symlink_status(p, ec))`, + respectively. The overload with argument `ec` returns `false` if an error occurs. + + + + +['Throws:] `filesystem_error`; the overload with argument `ec` throws + nothing. + + +] + + + +``` +bool [#is_socket]is_socket(file_status s) noexcept; +``` + +[: + + +['Returns:] `s.type() == socket_file` + + +] + + + +``` +bool [#is_socket2]is_socket(const path& p); +bool [#is_socket3]is_socket(const path& p, system::error_code& ec) noexcept; +``` + +[: + + +['Returns:] `is_socket(status(p))` or `is_socket(status(p, ec))`, + respectively. The overload with argument `ec` returns `false` if an error occurs. + + + + +['Throws:] `filesystem_error`; the overload with argument `ec` throws + nothing. + + +] + + + +``` +bool [#is_symlink]is_symlink(file_status s) noexcept; +``` + +[: + + +['Returns:] `s.type() == symlink_file` + + +] + + + +``` +bool [#is_symlink2]is_symlink(const path& p); +bool [#is_symlink3]is_symlink(const path& p, system::error_code& ec) noexcept; +``` + +[: + + +['Returns:] `is_symlink(symlink_status(p))` or `is_symlink(symlink_status(p, ec))`, + respectively. The overload with argument `ec` returns `false` if an error occurs. + + + + +['Throws:] `filesystem_error`; the overload with argument `ec` throws + nothing. + + +] + + + +``` +std::time_t [#creation_time]creation_time(const path& p); +std::time_t [#creation_time2]creation_time(const path& p, system::error_code& ec); +``` + +[: + + +['Returns:] The time of creation of the file to which `p` resolves. + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + + + +\[['Note:] Not all platforms support querying file creation time. Where not supported, the operation will fail with + `errc::function_not_supported` error code. ['—end note]\] + + +] + + + +``` +std::time_t [#last_write_time]last_write_time(const path& p); +std::time_t [#last_write_time2]last_write_time(const path& p, system::error_code& ec); +``` + +[: + + +['Returns:] The time of last data modification of `p`, determined as if by the + value of the ISO/IEC 9945 `[@http://www.opengroup.org/onlinepubs/000095399/basedefs/sys/stat.h.html stat]` structure member `st_mtime`  obtained + as if by ISO/IEC 9945 `[@http://www.opengroup.org/onlinepubs/000095399/functions/stat.html stat()]`. + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + +] + + + +``` +void [#last_write_time3]last_write_time(const path& p, const std::time_t new_time); +void [#last_write_time4]last_write_time(const path& p, const std::time_t new_time, system::error_code& ec); +``` + +[: + + +['Effects:] Sets the time of last data modification of the file + resolved to by `p` to `new_time`, as if by ISO/IEC + 9945 `[@http://www.opengroup.org/onlinepubs/000095399/functions/stat.html stat()]` followed by + ISO/IEC 9945 [@http://www.opengroup.org/onlinepubs/000095399/functions/utime.html `utime()`]. + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + + + +\[['Note:] A postcondition of `last_write_time(p) == new_time` is not specified since it might not hold for file systems + with coarse time granularity. ['—end note]\] + + +] + + + +``` +void [#permissions]permissions(const path& p, [@#symlink_perms perms] prms); +void permissions(const path& p, [@#symlink_perms perms] prms, system::error_code& ec); +``` + +[: + + + + ['Requires:] `!((prms & add_perms) && (prms & remove_perms))`. + + + + +['Effects:] Applies the effective permissions bits from `prms` to the file `p` resolves to, as if by + ISO/IEC 9945 `[@http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html fchmodat()]`. The effective permission bits are determined as + specified by the following table. + + + +[table + +[ + [[*bits present in `prms`]] + [[*Effective bits applied]] + ] + + +[ + [Neither `add_perms` nor `remove_perms`] + [`prms & perms_mask`] + ] + + +[ + [`add_perms`] + [ + + +`status(p).permissions() | (prms & [@#perms_mask perms_mask])` + +] + ] + + +[ + [`remove_perms`] + [`status(p)``.permissions() & ~(prms & [@#perms_mask perms_mask]) `] + ] + + ] + + + +\[['Note:] Conceptually permissions are viewed as bits, but the actual + implementation may use some other mechanism. ['—end note]\] + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + +] + + + +``` +path [#read_symlink]read_symlink(const path& p); +path read_symlink(const path& p, system::error_code& ec); +``` + +[: + + +['Returns:]  If `p` resolves to a symbolic + link, a `path` object containing the contents of that symbolic + link. Otherwise an empty `path` object. + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. \[['Note:] It is an error if `p` does not + resolve to a symbolic link. ['—end note]\] + + +] + + + +``` +path [#relative]relative(const path& p, system::error_code& ec); +``` + +[: + + +['Returns:] `relative(p, current_path(), ec)`. + + + + +['Throws:]  As specified in Error reporting. + + +] + + + +``` +path relative(const path& p, const path& base=current_path()); +path relative(const path& p, const path& base, system::error_code& ec); +``` + +[: + + +['Overview:] Returns `p` made relative to `base`. + Treats empty or identical paths as corner cases, not errors. Resolves symlinks + and normalizes both `p` and `base` before other + processing. + + + + +['Returns:] `[@#weakly_canonical weakly_canonical](p).[@#lex-relative lexically_relative]([@#weakly_canonical weakly_canonical](base))`. The second form returns `path()` + if an error occurs. + + + + +['Throws:] As specified in Error reporting. + + +] + + + +``` +bool [#remove]remove(const path& p); +bool [#remove2]remove(const path& p, system::error_code& ec); +``` + +[: + + +['Effects:]  If `exists(symlink_status(p,ec))`, it is + removed + as if by ISO/IEC 9945 `[@http://www.opengroup.org/onlinepubs/000095399/functions/remove.html remove()]`. + + + [: + + +\[['Note:] A symbolic link is itself removed, rather than the file it + resolves to being removed. ['—end note]\] + + + ] + + + + +['Postcondition:] `!exists(symlink_status(p))`. + + + + +['Returns:]  `false` if `p` did not exist, otherwise `true`. + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + +] + + + +``` +uintmax_t [#remove_all]remove_all(const path& p); +uintmax_t [#remove_all2]remove_all(const path& p, system::error_code& ec); +``` + +[: + + +['Effects:]  Recursively deletes the contents of `p` if it exists, + then deletes file `p` itself, + as if by ISO/IEC 9945 `[@http://www.opengroup.org/onlinepubs/000095399/functions/remove.html remove()]`. + + + [: + + +\[['Note:] A symbolic link is itself removed, rather than the file it + resolves to being removed. ['—end note]\] + + + ] + + + + +['Postcondition:] `!exists(p)` + + + + +['Returns:] The number of files removed. + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + +] + + + +``` +void [#rename]rename(const path& old_p, const path& new_p); +void [#rename2]rename(const path& old_p, const path& new_p, system::error_code& ec); +``` + +[: + + +['Effects:] Renames `old_p` to `new_p`, as if by + ISO/IEC 9945 `[@http://www.opengroup.org/onlinepubs/000095399/functions/rename.html rename()]`. + + + [: + + +\[['Note:] If `old_p` and `new_p` resolve to the + same existing file, no action is taken. Otherwise, if `new_p` resolves to an + existing non-directory file, it is removed, while if `new_p` resolves to an + existing directory, it is removed if empty on ISO/IEC 9945 but is an error on Windows. A symbolic link is itself renamed, rather than + the file it resolves to being renamed. ['—end note]\] + + + ] + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + +] + + + +``` +void [#resize_file]resize_file(const path& p, uintmax_t new_size); +void [#resize_file2]resize_file(const path& p, uintmax_t new_size, system::error_code& ec); +``` + +[: + + +['Postcondition:] `file_size() == new_size`. + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + + + +['Remarks:] Achieves its postconditions as if by ISO/IEC 9945 `[@http://www.opengroup.org/onlinepubs/000095399/functions/truncate.html truncate()]`. + + +] + + + +``` +space_info [#space]space(const path& p); +space_info [#space2]space(const path& p, system::error_code& ec); +``` + +[: + + +['Returns:] An object of type `[@#space_info space_info]`. The value of the `space_info` object is determined as if by + using ISO/IEC 9945 `[@http://www.opengroup.org/onlinepubs/000095399/functions/statvfs.html statvfs()]` to obtain an ISO/IEC 9945 struct + `[@http://www.opengroup.org/onlinepubs/000095399/basedefs/sys/statvfs.h.html statvfs]`, + and then multiplying its `f_blocks`, `f_bfree`, + and `f_bavail` members by its `f_frsize` member, + and assigning the results to the `capacity`, `free`, + and `available` members respectively. Any members for which the + value cannot be determined shall be set to -1. + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + +] + + + +``` +[@#file_status file_status] [#status]status(const path& p); +``` + +[: + + +['Effects: ]As if: + + + [: + +``` +system::error_code ec; +file_status result = status(p, ec); +if (result == status_error) + throw filesystem_error(['implementation-supplied-message], p, ec); +return result; +``` + + ] + + + + +['Returns:] See above. + + + + +['Throws:] `filesystem_error`. +\[['Note:] `result` values of `file_status(file_not_found)`and `file_status(type_unknown)` are not considered failures and do not + cause an exception to be +thrown.[' —end note]\] + + + ] + + + +``` +[@#file_status file_status] [#status2]status(const path& p, system::error_code& ec) noexcept; +``` + +[: + + +['Effects: ] + + + [: + + +If possible, determines the attributes + of the file `p` resolves to, as if by ISO/IEC 9945 `[@http://www.opengroup.org/onlinepubs/000095399/functions/stat.html stat()]`. + + + If, during attribute determination, the underlying file system API reports + an error, sets `ec` to indicate the specific error reported. + Otherwise, `ec.clear()`.[: + + +\[['Note:] This allows users to inspect the specifics of underlying + API errors even when the value returned by `status()` is not `file_status(status_error)`.  ['—end note]\] + + + ] + + + ] + + + + +['Returns:] + + + [: + + +If `ec != error_code()`: + + + + * If the specific error indicates that `p` cannot be resolved + because some element of the path does not exist, return ` + file_status(file_not_found)`. \[['Note:] ISO/IEC 9945 errors that + indicate this are ENOENT or ENOTDIR. Windows equivalents + include ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND, ERROR_INVALID_NAME, + ERROR_INVALID_PARAMETER, ERROR_BAD_PATHNAME, and ERROR_BAD_NETPATH. ['-- + end note]\] + +  + * Otherwise, if the specific error indicates that `p` can be resolved + but the attributes cannot be determined, return ` + file_status(type_unknown)`. \[['Note: ]For example, Windows + ERROR_SHARING_VIOLATION errors. For ISO/IEC 9945, the case never arises. ['—end + note]\] + +  + * Otherwise, return ` + file_status(status_error)`. + + [: + + +\[['Note:] These semantics distinguish between `p` being known not to exist, `p` existing but not being able to determine its attributes, + and there being an error that prevents even knowing if `p` exists. These + distinctions are important to some use cases. ['—end note]\] + + + ] + + + + +Otherwise, + + + + * If the attributes indicate a regular file, as if by ISO/IEC 9945 [@http://www.opengroup.org/onlinepubs/000095399/basedefs/sys/stat.h.html S_ISREG()], + return ` + file_status(regular_file)`. \[['Note:] ` +regular_file` implies appropriate `` operations + would succeed, assuming no hardware, permission, access, or file system + race + errors. Lack of +`regular_file` does not necessarily imply `` operations would +fail on a directory. +['—end note]\] + +  + * Otherwise, if the attributes indicate a directory, as if by ISO/IEC 9945 + [@http://www.opengroup.org/onlinepubs/000095399/basedefs/sys/stat.h.html S_ISDIR()], + return ` + file_status(directory_file)`. \[['Note:] `directory_file` implies ` +directory_iterator(p)`would succeed. +['—end note]\] + +  + * Otherwise, if the attributes indicate a block special file, as if by ISO/IEC 9945 + [@http://www.opengroup.org/onlinepubs/000095399/basedefs/sys/stat.h.html S_ISBLK()], + return ` + file_status(block_file)`. + +  + * Otherwise, if the attributes indicate a character special file, as if by ISO/IEC 9945 + [@http://www.opengroup.org/onlinepubs/000095399/basedefs/sys/stat.h.html S_ISCHR()], + return ` + file_status(character_file)`. + +  + * Otherwise, if the attributes indicate a fifo or pipe file, as if by + ISO/IEC 9945 + [@http://www.opengroup.org/onlinepubs/000095399/basedefs/sys/stat.h.html S_ISFIFO()], + return ` + file_status(fifo_file)`. + +  + * Otherwise, if the attributes indicate a socket, as if by ISO/IEC + 9945 + [@http://www.opengroup.org/onlinepubs/000095399/basedefs/sys/stat.h.html S_ISSOCK()], + return ` + file_status(socket_file)`. + +  + * Otherwise, return ` + file_status(type_unknown)`. + + ] + + + + +['Remarks:] If a symbolic link is encountered during pathname + resolution, + pathname resolution continues using the contents of the symbolic link. + + +] + + + +``` +bool [#status_known]status_known(file_status s) noexcept; +``` + +[: + + +['Returns:] `s.type() != status_error` + + +] + + + +``` +file_status [#symlink_status]symlink_status(const path& p); +file_status [#symlink_status2]symlink_status(const path& p, system::error_code& ec) noexcept; +``` + +[: + + +['Effects:]  Same as [@#status status()], above, + except that the attributes + of `p` are determined as if by ISO/IEC 9945 `[@http://www.opengroup.org/onlinepubs/000095399/functions/lstat.html lstat()]`. + + +] + + +[: + + +['Returns:] Same as [@#status status()], above, except + that if the attributes indicate a symbolic link, as if by ISO/IEC 9945 [@http://www.opengroup.org/onlinepubs/000095399/basedefs/sys/stat.h.html S_ISLNK()], return `file_status(symlink_file)`. + + + + +['Remarks:] Pathname resolution terminates if `p` names a symbolic link. + + + + +['Throws:] `filesystem_error`; overload with `error_code&` throws + nothing. + + +] + + + +``` +path [#system_complete]system_complete(const path& p); +path [#system_complete2]system_complete(const path& p, system::error_code& ec); +``` + +[: + + +['Effects:] Composes an absolute path from `p`, using the + same rules used by the operating system to resolve a path passed as the + filename argument to standard library open functions. + + + + +['Returns:] The composed path. + + + + +['Postcondition:] For the returned path, `rp`, `rp.is_absolute()` is true. + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + + + +\[['Note:] For ISO/IEC 9945, `system_complete(p)` has the same semantics as `[@#absolute absolute](p, [@#current_path current_path]())`. + + + + +[#windows_effects]For ['Windows], `system_complete(p)` has the + same semantics as `[@#absolute absolute](p, [@#current_path current_path]())` if `p.is_absolute() || !p.has_root_name()` or `p` and `base` have the same `root_name()`. + Otherwise it acts like `[@#absolute absolute](p, kinky)`, where `kinky` is the current directory for the `p.root_name()` drive. This will + be the current directory of that drive the last time it was set, and thus may + be [*residue left over from a prior program] run by the command + processor! Although these semantics are often useful, they are also very + error-prone. + + +] + + + +``` +path [#temp_directory_path]temp_directory_path(); +path temp_directory_path(system::error_code& ec); +``` + +[: + + +['Returns:] A directory path suitable for temporary files under the + conventions of the operating system. The specifics of how this path is + determined are implementation defined. An error shall be reported if` !exists(p) + || !is_directory(p)`, where `p` is the path to be returned. + + + + +ISO/IEC 9945: The path supplied by the first environment variable found in the + list TMPDIR, TMP, TEMP, TEMPDIR. If none of these are found, `"/tmp"`, + or, if macro `__ANDROID__ `is defined, `"/data/local/tmp"`. + + + + +['Windows:] The path reported by the ['Windows] `GetTempPath` API function. + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + + + +\[['Note: ]The `temp_directory_path()` name was chosen to emphasize that the return is a + path, not just a single directory name.  ['—end note]\] + + +] + + + +``` +path [#unique_path]unique_path(const path& model="%%%%-%%%%-%%%%-%%%%"); +path unique_path(system::error_code& ec); +path unique_path(const path& model, system::error_code& ec); +``` + +[: + + +The `unique_path` function generates a path name suitable for + creating temporary files, including directories. The name is based + on a model that uses the percent sign character to specify replacement by a + random hexadecimal digit. Where model is not specified, a default model + equivalent to "%%%%-%%%%-%%%%-%%%%" is used. \[['Note:] The more + bits of randomness in the generated path name, the less likelihood of prior + existence or being guessed. Each replacement hexadecimal digit in the model + adds four bits of randomness. The default model thus provides 64 bits of + randomness. This is sufficient for most applications. ['—end note]\] + + + + +['Returns:] A path identical to `model`, except that each + occurrence of a percent sign character is replaced by a random hexadecimal + digit character in the range 0-9, a-f. + + + + +['Throws:] As specified in [@#Error-reporting Error reporting]. + + + + +['Remarks:] Implementations are encouraged to obtain the required + randomness via a [@http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator cryptographically secure pseudo-random number generator], such as one + provided by the operating system. \[['Note]: Such generators may block + until sufficient entropy develops. ['—end note]\] + + +] + + + +``` +path [#weakly_canonical]weakly_canonical(const path& p, const path& base=current_path()); +path weakly_canonical(const path& p, system::error_code& ec); +path weakly_canonical(const path& p, const path& base, system::error_code& ec); +``` + +[: + + +['Overview:] Returns `p` with symlinks resolved and the + result normalized. + + + + +['Effects:] Let `head` be the path composed of the leading + elements of `p` that exist and `tail` — from the rest of `p`. + Where not specified, `base` is obtained from `[@#current_path current_path]()` or `[@#current_path current_path](ec)` + Calls `[@#canonical canonical](head, base)` or `[@#canonical canonical](head, base, ec)`, + appends `tail` to the returned path as if by using `operator/`. + The result is then normalized and returned. + + + + +['Postcondition:] The returned path is in + [@#normal-form normal form]. + + + + +['Remarks:] Uses `operator/=` to compose the returned path. + Uses the `status` function to determine existence. + + + + +['Remarks:] Implementations are encouraged to avoid unnecessary + normalization such as when `canonical` has already been called on + the entirety of `p`. + + + + +['Throws:]  As specified in Error reporting. + + +] + + + + + + + + +[h3 [#File-streams]File streams] + + +[h4 [@../../../boost/filesystem/fstream.hpp ] header] + + + +Replacements are provided for the file stream classes from the C++ standard +library's `` header. These replacement classes +publicly inherit from the standard library classes. In the Boost.Filesystem +version, constructors and open functions take `const path&` arguments +instead of `const char*` arguments. There are no other differences in syntax or +semantics. + + + +``` +namespace boost +{ + namespace filesystem + { + template < class charT, class traits = std::char_traits > + class basic_filebuf : public std::basic_filebuf + { + public: + basic_filebuf* + open(const path& p, std::ios_base::openmode mode); + }; + + template < class charT, class traits = std::char_traits > + class basic_ifstream : public std::basic_ifstream + { + public: + explicit basic_ifstream(const path& p, std::ios_base::openmode mode=std::ios_base::in) + void open(const path& p, std::ios_base::openmode mode=std::ios_base::in); + }; + + template < class charT, class traits = std::char_traits > + class basic_ofstream : public std::basic_ofstream + { + public: + explicit basic_ofstream(const path& p, std::ios_base::openmode mode=std::ios_base::out); + void open(const path& p, std::ios_base::openmode mode=std::ios_base::out); + }; + + template < class charT, class traits = std::char_traits > + class basic_fstream : public std::basic_fstream + { + public: + explicit basic_fstream(const path& p, + std::ios_base::openmode mode=std::ios_base::in | std::ios_base::out); + void open(const path& p, + std::ios_base::openmode mode=std::ios_base::in | std::ios_base::out); + }; + + typedef basic_filebuf filebuf; + typedef basic_ifstream ifstream; + typedef basic_ofstream ofstream; + typedef basic_fstream fstream; + + typedef basic_filebuf wfilebuf; + typedef basic_ifstream wifstream; + typedef basic_fstream wfstream; + typedef basic_ofstream wofstream; + + } // namespace filesystem +} // namespace boost +``` + + + + +[h4 [@../../../boost/filesystem/cstdio.hpp ] header] + + + +This header provides a `std::fopen` overload from `` C++ standard library header. +The overload accepts `const path&` as its first argument instead of `const char*` and has no +other differences from its standard counterpart. + + + +``` +namespace boost +{ + namespace filesystem + { + std::FILE* fopen(const path& p, const char* mode); + + } // namespace filesystem +} // namespace boost +``` + + + +[h2 [#path-decomposition-table]Path decomposition table] + + + +The table is generated by a program compiled with the Boost implementation. + + + + +Shaded entries indicate cases where ISO/IEC 9945 (POSIX) and Windows implementations yield different results. The top value is the +ISO/IEC 9945 result and the bottom value is the Windows result. + + + +[table + +[[[*Constructor +argument]] +[[*Iteration +over +Elements]] +[[*`string()`]] +[[*`generic_ +string()`]] +[[*`root_ +path()`]] +[[*`root_ +name()`]] +[[*`root_ +directory()`]] +[[*`relative_ +path()`]] +[[*`parent_ +path()`]] +[[*`filename()`]] +] + + +[ +[['empty]] +[['empty]] +[['empty]] +[['empty]] +[['empty]] +[['empty]] +[['empty]] +[['empty]] +[['empty]] +[['empty]] +] + + +[ +[`.`] +[`.`] +[`.`] +[`.`] +[['empty]] +[['empty]] +[['empty]] +[`.`] +[['empty]] +[`.`] +] + + +[ +[`..`] +[`..`] +[`..`] +[`..`] +[['empty]] +[['empty]] +[['empty]] +[`..`] +[['empty]] +[`..`] +] + + +[ +[`foo`] +[`foo`] +[`foo`] +[`foo`] +[['empty]] +[['empty]] +[['empty]] +[`foo`] +[['empty]] +[`foo`] +] + + +[ +[`/`] +[`/`] +[`/`] +[`/`] +[`/`] +[['empty]] +[`/`] +[['empty]] +[['empty]] +[`/`] +] + + +[ +[`/foo`] +[`/,foo`] +[`/foo`] +[`/foo`] +[`/`] +[['empty]] +[`/`] +[`foo`] +[`/`] +[`foo`] +] + + +[ +[`foo/`] +[`foo,.`] +[`foo/`] +[`foo/`] +[['empty]] +[['empty]] +[['empty]] +[`foo/`] +[`foo`] +[`.`] +] + + +[ +[`/foo/`] +[`/,foo,.`] +[`/foo/`] +[`/foo/`] +[`/`] +[['empty]] +[`/`] +[`foo/`] +[`/foo`] +[`.`] +] + + +[ +[`foo/bar`] +[`foo,bar`] +[`foo/bar`] +[`foo/bar`] +[['empty]] +[['empty]] +[['empty]] +[`foo/bar`] +[`foo`] +[`bar`] +] + + +[ +[`/foo/bar`] +[`/,foo,bar`] +[`/foo/bar`] +[`/foo/bar`] +[`/`] +[['empty]] +[`/`] +[`foo/bar`] +[`/foo`] +[`bar`] +] + + +[ +[`//net`] +[`//net`] +[`//net`] +[`//net`] +[`//net`] +[`//net`] +[['empty]] +[['empty]] +[['empty]] +[`//net`] +] + + +[ +[`//net/foo`] +[`//net,/,foo`] +[`//net/foo`] +[`//net/foo`] +[`//net/`] +[`//net`] +[`/`] +[`foo`] +[`//net/`] +[`foo`] +] + + +[ +[`///foo///`] +[`/,foo,.`] +[`///foo///`] +[`///foo///`] +[`/`] +[['empty]] +[`/`] +[`foo///`] +[`///foo`] +[`.`] +] + + +[ +[`///foo///bar`] +[`/,foo,bar`] +[`///foo///bar`] +[`///foo///bar`] +[`/`] +[['empty]] +[`/`] +[`foo///bar`] +[`///foo`] +[`bar`] +] + + +[ +[`/.`] +[`/,.`] +[`/.`] +[`/.`] +[`/`] +[['empty]] +[`/`] +[`.`] +[`/`] +[`.`] +] + + +[ +[`./`] +[`.,.`] +[`./`] +[`./`] +[['empty]] +[['empty]] +[['empty]] +[`./`] +[`.`] +[`.`] +] + + +[ +[`/..`] +[`/,..`] +[`/..`] +[`/..`] +[`/`] +[['empty]] +[`/`] +[`..`] +[`/`] +[`..`] +] + + +[ +[`../`] +[`..,.`] +[`../`] +[`../`] +[['empty]] +[['empty]] +[['empty]] +[`../`] +[`..`] +[`.`] +] + + +[ +[`foo/.`] +[`foo,.`] +[`foo/.`] +[`foo/.`] +[['empty]] +[['empty]] +[['empty]] +[`foo/.`] +[`foo`] +[`.`] +] + + +[ +[`foo/..`] +[`foo,..`] +[`foo/..`] +[`foo/..`] +[['empty]] +[['empty]] +[['empty]] +[`foo/..`] +[`foo`] +[`..`] +] + + +[ +[`foo/./`] +[`foo,.,.`] +[`foo/./`] +[`foo/./`] +[['empty]] +[['empty]] +[['empty]] +[`foo/./`] +[`foo/.`] +[`.`] +] + + +[ +[`foo/./bar`] +[`foo,.,bar`] +[`foo/./bar`] +[`foo/./bar`] +[['empty]] +[['empty]] +[['empty]] +[`foo/./bar`] +[`foo/.`] +[`bar`] +] + + +[ +[`foo/..`] +[`foo,..`] +[`foo/..`] +[`foo/..`] +[['empty]] +[['empty]] +[['empty]] +[`foo/..`] +[`foo`] +[`..`] +] + + +[ +[`foo/../`] +[`foo,..,.`] +[`foo/../`] +[`foo/../`] +[['empty]] +[['empty]] +[['empty]] +[`foo/../`] +[`foo/..`] +[`.`] +] + + +[ +[`foo/../bar`] +[`foo,..,bar`] +[`foo/../bar`] +[`foo/../bar`] +[['empty]] +[['empty]] +[['empty]] +[`foo/../bar`] +[`foo/..`] +[`bar`] +] + + +[ +[`c:`] +[`c:`] +[`c:`] +[`c:`] +[['empty] +`c:`] +[['empty] +`c:`] +[['empty]] +[`c:` +['empty]] +[['empty]] +[`c:`] +] + + +[ +[`c:/`] +[`c:,.` +`c:,/`] +[`c:/`] +[`c:/`] +[['empty] +`c:/`] +[['empty] +`c:`] +[['empty] +`/`] +[`c:/` +['empty]] +[`c:`] +[`.` +`/`] +] + + +[ +[`c:foo`] +[`c:foo` +`c:,foo`] +[`c:foo`] +[`c:foo`] +[['empty] +`c:`] +[['empty] +`c:`] +[['empty]] +[`c:foo` +`foo`] +[['empty] +`c:`] +[`c:foo` +`foo`] +] + + +[ +[`c:/foo`] +[`c:,foo` +`c:,/,foo`] +[`c:/foo`] +[`c:/foo`] +[['empty] +`c:/`] +[['empty] +`c:`] +[['empty] +`/`] +[`c:/foo` +`foo`] +[`c:` +`c:/`] +[`foo`] +] + + +[ +[`c:foo/`] +[`c:foo,.` +`c:,foo,.`] +[`c:foo/`] +[`c:foo/`] +[['empty] +`c:`] +[['empty] +`c:`] +[['empty]] +[`c:foo/` +`foo/`] +[`c:foo`] +[`.`] +] + + +[ +[`c:/foo/`] +[`c:,foo,.` +`c:,/,foo,.`] +[`c:/foo/`] +[`c:/foo/`] +[['empty] +`c:/`] +[['empty] +`c:`] +[['empty] +`/`] +[`c:/foo/` +`foo/`] +[`c:/foo`] +[`.`] +] + + +[ +[`c:/foo/bar`] +[`c:,foo,bar` +`c:,/,foo,bar`] +[`c:/foo/bar`] +[`c:/foo/bar`] +[['empty] +`c:/`] +[['empty] +`c:`] +[['empty] +`/`] +[`c:/foo/bar` +`foo/bar`] +[`c:/foo`] +[`bar`] +] + + +[ +[`prn:`] +[`prn:`] +[`prn:`] +[`prn:`] +[['empty] +`prn:`] +[['empty] +`prn:`] +[['empty]] +[`prn:` +['empty]] +[['empty]] +[`prn:`] +] + + +[ +[`c:\\`] +[`c:\\` +`c:,/`] +[`c:\\`] +[`c:\\` +`c:/`] +[['empty] +`c:\\`] +[['empty] +`c:`] +[['empty] +`\\`] +[`c:\\` +['empty]] +[['empty] +`c:`] +[`c:\\` +`\\`] +] + + +[ +[`c:foo`] +[`c:foo` +`c:,foo`] +[`c:foo`] +[`c:foo`] +[['empty] +`c:`] +[['empty] +`c:`] +[['empty]] +[`c:foo` +`foo`] +[['empty] +`c:`] +[`c:foo` +`foo`] +] + + +[ +[`c:\\foo`] +[`c:\\foo` +`c:,/,foo`] +[`c:\\foo`] +[`c:\\foo` +`c:/foo`] +[['empty] +`c:\\`] +[['empty] +`c:`] +[['empty] +`\\`] +[`c:\\foo` +`foo`] +[['empty] +`c:\\`] +[`c:\\foo` +`foo`] +] + + +[ +[`c:foo\\`] +[`c:foo\\` +`c:,foo,.`] +[`c:foo\\`] +[`c:foo\\` +`c:foo/`] +[['empty] +`c:`] +[['empty] +`c:`] +[['empty]] +[`c:foo\\` +`foo\\`] +[['empty] +`c:foo`] +[`c:foo\\` +`.`] +] + + +[ +[`c:\\foo\\`] +[`c:\\foo\\` +`c:,/,foo,.`] +[`c:\\foo\\`] +[`c:\\foo\\` +`c:/foo/`] +[['empty] +`c:\\`] +[['empty] +`c:`] +[['empty] +`\\`] +[`c:\\foo\\` +`foo\\`] +[['empty] +`c:\\foo`] +[`c:\\foo\\` +`.`] +] + + +[ +[`c:\\foo/`] +[`c:\\foo,.` +`c:,/,foo,.`] +[`c:\\foo/`] +[`c:\\foo/` +`c:/foo/`] +[['empty] +`c:\\`] +[['empty] +`c:`] +[['empty] +`\\`] +[`c:\\foo/` +`foo/`] +[`c:\\foo`] +[`.`] +] + + +[ +[`c:/foo\\bar`] +[`c:,foo\\bar` +`c:,/,foo,bar`] +[`c:/foo\\bar`] +[`c:/foo\\bar` +`c:/foo/bar`] +[['empty] +`c:/`] +[['empty] +`c:`] +[['empty] +`/`] +[`c:/foo\\bar` +`foo\\bar`] +[`c:` +`c:/foo`] +[`foo\\bar` +`bar`] +] + +] + + + +[h2 [#windows-path-prefixes]Long paths on Windows and the +[*\\\\?\\] namespace prefix] + + + +The Microsoft Windows "Maximum Path Length Limitation" specifies: + + +[: + + +In the Windows API (with some exceptions ...), the maximum length for a path +is `MAX_PATH`, which is defined as 260 characters. + + + + +The Windows API has many functions that also have Unicode versions to permit +an extended-length path for a maximum total path length of 32,767 characters. +... To specify an extended-length path, use the "\\\\?\\" prefix. For +example, "\\\\?\\D:\\very long path". ['\[C++ string literals +require backslashes be doubled, of course.\]] + + +] + + + + +Because most Boost.Filesystem operational functions just pass the contents of +a class path object to the Windows API, they do work with the extended-length +prefixes. But some won't work, because to the limitations imposed by Windows. + + + + +Effectively, the "\\\\?\\" prefix informs the underlying Windows API +that the path identifies an object in the Win32 filesystem namespace and disables +most of the internal path processing, including normalization, by the Windows API. +While it lifts the length limitation, this imposes a number of other restrictions on +the acceptable paths that are listed in the section below. There are a number of +other prefixes that have different special meanings, such as "\\\\.\\" (a local +device namespace prefix) and "\\??\\" (NT object namespace prefix). Note that +UNC paths can be extended with the prefixes by referring to a special "UNC" +device. For example, "\\\\server\\share" can be extended as "\\\\?\\UNC\\server\\share". + + + + +In terms of Boost.Filesystem, the namespace prefixes are considered as parts of the path's +root name. For example, the root name of "\\\\?\\c:\\foo" is "\\\\?\\c:". +This interpretation is chosen to allow root paths to be iterable, that is you can list +the contents of the "\\\\?\\c:\\" directory, provided that drive C: exists and you have +the necessary permissions. ['\[Note: You can't list the contents of "\\\\?\\" +as such path does not exist.\]] + + + + +[h3 Cautions for paths with namespace prefixes] + + + * Individual components of a path are still are limited to whatever is + supported for the particular filesystem, commonly 255 characters. + * Only backslashes are acceptable as directory separators. Slashes are + not treated as separators. + * All paths must be absolute and must not contain "." or ".." components. + * Once an absolute path grows beyond 260 characters, it is essentially + poisoned and all operations must use extended-length prefixes. So even a + simple operation like `create_directory("a")` will fail if the + absolute path of the resulting directory would exceed 260 characters. + * Certain Boost.Filesystem functions that decompose their argument path and + then work on individual relative directories or files will not work properly + with namespace prefix paths. + + + +[h2 [#Acknowledgements]Acknowledgements] + + + +This Filesystem Library is dedicated to my wife, Sonda, who provided the +support necessary to see both a trial implementation and the proposal itself +through to completion. She gave me the strength to continue after a difficult +year of cancer treatment in the middle of it all. + + + + +Many people contributed technical comments, ideas, and suggestions to the +Boost Filesystem Library. See [@index.htm#Change-history Version history]. + + + + +Dietmar Kühl contributed the original Boost Filesystem Library `directory_iterator` design. Peter Dimov, Walter Landry, Rob Stewart, and Thomas +Witt were particularly helpful in refining the library. + + + + +The `create_directories`, `extension`, `basename`, and `replace_extension` functions +were developed by Vladimir Prus. The `temp_directory_path` function was +contributed by Jeff Flinn. David Svoboda suggested the `canonical` function and +provided pseudo-code. + + + + +Howard Hinnant and John Maddock reviewed a draft of the version 2 proposal, and +identified a number of mistakes or weaknesses, resulting in a more polished +final document. + + + + +Peter Dimov suggested a single class `path`, with member templates to adapt to +multiple string types. His idea became the basis for the version 3 path design. + + + +[h2 [#References]References] + + +[table + +[ + [\[[#ISO_POSIX]ISO/IEC 9945\]] + [ISO/IEC 9945:2003, IEEE Std 1003.1-2001, and The Open Group + Base Specifications, Issue 6. Also known as The Single UNIX® + Specification, Version 3. Available from each of the organizations involved + in its creation. For example, read online or download from [@http://www.unix.org/single_unix_specification/ www.unix.org/single_unix_specification/]. The ISO JTC1/SC22/WG15 - + POSIX homepage is [@http://www.open-std.org/jtc1/sc22/WG15/ www.open-std.org/jtc1/sc22/WG15/]] + ] + + +[ + [\[Abrahams\]] + [Dave Abrahams, Error and Exception Handling, [@http://www.boost.org/more/error_handling.html www.boost.org/more/error_handling.html]] + ] + +] + + + + +© Copyright Beman Dawes, 2002, 2006, 2007, 2009, 2010, 2011 + + + + +© Copyright Andrey Semashev, 2019-2024 + + + + +Distributed under the Boost Software License, Version 1.0. See +[@http://www.boost.org/LICENSE_1_0.txt www.boost.org/LICENSE_1_0.txt] + + diff --git a/doc/reference.qbk b/doc/reference.qbk new file mode 100644 index 000000000..b736cd61a --- /dev/null +++ b/doc/reference.qbk @@ -0,0 +1,27 @@ +[/ + / Copyright Andrey Semashev 2024. + / + / Distributed under the Boost Software License, Version 1.0. + / (See accompanying file LICENSE_1_0.txt or copy at + / https://www.boost.org/LICENSE_1_0.txt) + /] + +[section:reference Reference] + +[section:path Path] + +[section:iterators Iterators] + +[endsect] + +[xinclude path_reference.xml] + +[endsect] + +[xinclude operations_reference.xml] +[xinclude directory_reference.xml] +[xinclude file_status_reference.xml] +[xinclude exception_reference.xml] +[xinclude io_reference.xml] + +[endsect] diff --git a/doc/relative_proposal.qbk b/doc/relative_proposal.qbk new file mode 100644 index 000000000..a18ef4ef3 --- /dev/null +++ b/doc/relative_proposal.qbk @@ -0,0 +1,964 @@ +[/ + / Copyright Andrey Semashev 2024. + / + / Distributed under the Boost Software License, Version 1.0. + / (See accompanying file LICENSE_1_0.txt or copy at + / http://www.boost.org/LICENSE_1_0.txt) + /] + +[template super[x]''''''[x]''''''] +[template sub[x]''''''[x]''''''] + +[h1 Filesystem Relative Proposal] + + + + +[table + +[ + [ +[@../../../index.htm +[$../../../boost.png]]] + [ + Filesystem Relative + + Draft Proposal + ] + ] + +] + + + +[table + +[ + [[@index.htm Home]    + [@tutorial.html Tutorial]    + [@reference.html Reference]    + [@faq.htm FAQ]    + [@release_history.html Releases]    + [@portability_guide.htm Portability]    + [@v4.html V4]    + [@v3.html V3 Intro]    + [@v3_design.html V3 Design]    + [@deprecated.html Deprecated]    + [@issue_reporting.html Bug Reports ]   + ] + ] + +] + + + + +[@#Introduction + Introduction] + +    [@#Acknowledgement Acknowledgement] + +    [@#Preliminary-implementation Preliminary implementation] + +[@#Requirements Requirements] + +[@#Issues Issues] + +[@#Design-decisions + Design decisions] + +    [@#Provide-separate-relative Provide separate lexical and + operational `relative` functions] + +    [@#Provide-separate-proximate Provide +separate lexical and operational `proximate` functions] + +    [@#Add-lexical-functions Add lexical functions as `path` member functions] + +    [@#Provide-normal Provide a non-member function +`lexically_normal` returning a + normal form path] + +    [@#Provide-weakly Provide a `weakly_canonical` operational function] + +    [@#just-work Resolve issues in ways that "just work" for users] + +    [@#mismatch Specify `lexical relative` in terms + of `std::mismatch`] + +    [@#Specify-op-rel-weakly Specify operational `relative` in terms of ` + weakly_canonical`] + +    [@#Specify-op-rel-lex-rel Specify operational `relative` in terms of + `lexically + relative`] + +[@#Proposed-wording Proposed wording] + +    [@#Define-normal-form Define ['normal form]] + +    [@#New-class-path-member-functions New class path member functions] + +        [@#Synopsis-path Synopsis] + +        [@#Specification-path Specification] + +    [@#operational-functions New operational functions] + +        [@#Synopsis-ops Synopsis] + +        [@#Specification-ops Specification] + + + + +[h2 + [#Introduction]Introduction] + + + + +There have been requests for a Filesystem library relative function for at + least ten years. + + + + + + + The requested functionality seems simple - given two paths with a common + prefix, return the non-common suffix portion of one of the paths such that + it is relative to the other path. + + + + + + + In terms of the Filesystem library, + + + +[: + +``` +path p("/a/b/c"); +path base("/a/b"); +path rel = relative(p, base); // the requested function +cout << rel << endl; // outputs "c" +assert(absolute(rel, base) == p); +``` + +] + + + + +If that was all there was to it, the Filesystem library would have had a +`relative` function years ago. + + +[: + + +Blocking issues: Clashing requirements, symlinks, directory placeholders (['dot], +['dot-dot]), user-expectations, corner cases. + + +] + + + +[h3 [#Acknowledgement]Acknowledgement] + + + +A paper by Jamie Allsop, ['Additions to Filesystem supporting Relative Paths], +is what broke my mental logjam. Much of what follows is based directly on +Jamie's analysis and proposal. The `weakly_canonical` function and +aspects of the semantic specifications are my contributions. Mistakes, of +course, are mine. + + + +[h3 [#Preliminary-implementation]Preliminary implementation] + + + +A preliminary implementation is available in the +[@https://github.com/boostorg/filesystem/tree/feature/relative2 +feature/relative2] branch of the Boost Filesystem Git repository. See +[@https://github.com/boostorg/filesystem/tree/feature/relative2 +github.com/boostorg/filesystem/tree/feature/relative2] + + + +[h2 [#Requirements]Requirements] + + + +[*[#Requirement-1]Requirement 1:] Some uses require symlinks be followed; i.e. the path must be resolved in + the actual file system. + + + + +[*[#Requirement-2]Requirement 2: ]Some uses require symlinks not be followed; i.e. the path must not be + resolved in the actual file system. + + + + +[*[#Requirement-3]Requirement 3: ]Some uses require removing redundant current directory (['dot]) + or parent directory (['dot-dot]) placeholders. + + + + +[*[#Requirement-4]Requirement 4: ]Some uses do not require removing redundant current directory (['dot]) + or parent directory (['dot-dot]) placeholders since the path is known to be already in normal form. + + + +[h2 [#Issues]Issues] + + + +[*[#Issue-1]Issue 1:] What happens if `p` +and `base` are themselves relative? + + + + +[*[#Issue-2]Issue 2:] What happens if there is no common prefix? Is this an error, the whole of + `p` is relative to `base`, or something else? + + + + +[*[#Issue-3]Issue 3:] What happens if `p`, `base`, or both are empty? + + + + +[*[#Issue-4]Issue 4:] What happens if `p` and `base` are the same? + + + + +[*[#Issue-5]Issue 5:] How is the "common prefix" determined? + + + + +[*[#Issue-6]Issue 6:] What happens if portions of `p` or `base` exist but + the entire path does not exist and yet symlinks need to be followed? + + + + +[*[#Issue-7]Issue 7:] What happens when a symlink in the existing portion of a path is affected + by a directory (['dot-dot]) placeholder in a later non-existent portion of + the path? + + + + +[*[#Issue-8]Issue 8:] Overly complex semantics (and thus +specifications) in preliminary designs made reasoning about uses difficult. + + + + +[*[#Issue-9]Issue 9: ]Some uses never have redundant current directory (['dot]) + or parent directory (['dot-dot]) placeholders, so a removal operation + would be an unnecessary expense although otherwise harmless. + + + + +[h2 + [#Design-decisions]Design decisions] + + + +[h4 + [#Provide-separate-relative]Provide separate lexical and + operational `relative` functions] + + + + + + Resolves the conflict between [@#Requirement-1 requirement 1] + and [@#Requirement-2 requirement 2] and ensures both + requirements are met. + + + + + + + A purely lexical function is needed by users working with directory + hierarchies that do not actually exist. + + + + + + + An operational function that queries the current file system for existence + and follows symlinks is needed by users working with actual existing + directory hierarchies. + + + + +[h4 + [#Provide-separate-proximate]Provide separate lexical and operational + `proximate` functions] + + + + + + Although not the only possibility, a likely fallback when the relative + functions cannot find a relative path is to return the path being made relative. As + a convenience, the `proximate` functions do just that. + + + + +[h4 + [#Add-lexical-functions]Add lexical functions as + `path` member functions] + + + + + + The Filesystem library is unusual in that it has several functions with + both lexical (i.e. cheap) and operational (i.e. expensive due to file + system access) forms with differing semantics. It is important that users + choose the form that meets their application's specific needs. The library + has always made the distinction via the convention of lexical functions + being members of class `path`, while operational functions are + non-member functions. The lexical functions proposed here also use the + name prefix `lexically_` to drive home the distinction. + + + + + + + For the contrary argument, see Sutter and Alexandrescu, ['C++ Coding Standards], 44: + "Prefer writing nonmember nonfriend functions", and Meyers, ['Effective C++ Third Edition], 23: + "Prefer non-member non-friend functions to member functions." + + + + +[h4 + [#Provide-normal]Provide[* ]a non-member function ` + [@#normal lexically_normal]` returning a + [@#normal-form normal form] path] + + + + + + Enables resolution of [@#Requirement-3 requirement 3] and + [@#Requirement-4 requirement 4] in a way consistent with + [@#Issue-9 issue 9]. Is a contributor to the resolution of + [@#Issue-8 issue 8]. + + + + + + + "Normalization" is the process of removing redundant current directory (['dot]) + , parent + directory (['dot-dot]), and directory separator elements. + + + + + + + Normalization is a byproduct the current `canonical` function. + But for the path returned by the + proposed `[@#weakly_canonical weakly_canonical]` function, + only any leading canonic portion is in canonical form. So any trailing + portion of the returned path has not been normalized. + + + + + + + Jamie Allsop has proposed adding a separate normalization function returning a + path, and I agree with him. + + + + + + + Boost.filesystem has a deprecated non-const normalization function that + modifies the path, but I agree with Jamie that a function returning a path + is a better solution. + + + + +[h4 + [#Provide-weakly]Provide[* ]a `[@#weakly_canonical weakly_canonical]` operational function] + + + + + + Resolves [@#Issue-6 issue 6], [@#Issue-7 issue 7], + [@#Issue-9 issue 9], and is a contributor to the resolution of + [@#Issue-8 issue 8]. + + + + + + + The operational function + `weakly_canonical(p)` returns a path composed of ` + canonical(x)/y`, where `x` is a path composed of the + longest leading sequence of elements in `p` that exist, and + `y` is a path composed of the remaining trailing non-existent elements of + `p` if any. "`weakly`" refers to weakened existence + requirements compared to the existing canonical function. + + + + + * Having `weakly_canonical` as a separate function, and then + specifying the processing of operational `relative` arguments in + terms of calls to `weakly_canonical` makes it much easier to + specify the operational `relative` function and reason about it. + The difficulty of reasoning about operational `relative` + semantics before the invention of `weakly_canonical` was what led to its + initial development. + * Having `weakly_canonical` as a separate function also allows + use in other contexts. + * Specifying the return be in [@#normal-form normal form] is an + engineering trade-off to resolve [@#Issue-7 issue 7] in a way that + just works for most use cases. + * Specifying normative encouragement to not perform unneeded normalization + is a reasonable resolution for [@#Issue-9 issue 9]. + + + +[h4 + Resolve issues in ways that "[#just-work]just work" for users] + + + + + + Resolves issues [@#Issue-1 1], [@#Issue-2 2], + [@#Issue-3 3], [@#Issue-4 4], [@#Issue-7 6], + and [@#Issue-7 7]. Is a contributor to the resolution of + [@#Issue-8 issue 8]. + + + + + + + The "just works" approach was suggested by Jamie Allsop. It is implemented + by specifying a reasonable return value for all of the "What happens + if..." corner case issues, rather that treating them as hard errors + requiring an exception or error code. + + + + +[h4 + Specify [@#lex-proximate `lexically relative`] in terms + of `std::[#mismatch]mismatch`] + + + + + + Resolves [@#Issue-5 issue 5]. Is a contributor to the + resolution of [@#Issue-8 issue 8]. + + + + +[h4 + [#Specify-op-rel-weakly]Specify [@#op-proximate operational `relative`] in terms of ` + [@#weakly_canonical weakly_canonical]`] + + + + + + Is a contributor to the resolution of [@#Issue-8 issue 8]. + + + + + * Covers a wide range of uses cases since a single function works for + existing, non-existing, and partially existing paths. + * Works correctly for partially existing paths that contain symlinks. + + + +[h4 + [#Specify-op-rel-lex-rel]Specify [@#op-proximate operational `relative`] in terms of + [@#lex-proximate `lexically + relative`]] + + + + + + Is a contributor to the resolution of [@#Issue-5 issue 5] and + [@#Issue-8 issue 8]. + + + + + + + If would be confusing to users and difficult to specify correctly if the + two functions had differing semantics: + + + + * When either or both paths are empty. + * When all elements of the two paths match exactly. + * Because different matching algorithms were used. + * Because although the same matching algorithm was used, it was applied in different ways. + + + + + + These problems are avoided by specifying operational `relative` + in terms of lexical `relative` after preparatory + calls to operational functions. + + + + +[h2 [#Proposed-wording]Proposed wording] + + + + +['"Overview:" sections below are +non-normative experiments attempting to make the normative reference +specifications easier to grasp.] + + + + +[h3 [#Define-normal-form]Define ['normal form]] + + + + +A path is in [*['[#normal-form]normal form]] if it has no +redundant current directory (['dot]) or parent directory (['dot-dot]) +elements. The normal form for an empty path is an empty path. The normal form +for a path ending in a ['directory-separator] that is not the root directory +is the same path with a current directory (['dot]) element appended. + + + + + +['The last sentence above is not +necessary for POSIX-like or Windows-like operating systems, but supports systems +like OpenVMS that use different syntax for directory and regular-file names.] + + + + +[h3 [#New-class-path-member-functions]New class path member functions] + + + +[h4 [#Synopsis-path]Synopsis] + + + +``` +path lexically_normal() const; +path lexically_relative(const path& base) const; +path lexically_proximate(const path& base) const; +``` + + + +[h4 [#Specification-path]Specification] + + + + +``` +path [#lex-normal]lexically_normal() const; +``` + +[: + + +['Overview:] Returns `*this` with redundant current directory +(['dot]), parent directory (['dot-dot]), and ['directory-separator] elements removed. + + + + +['Returns:] `*this` in [@#normal-form normal form]. + + + + +['Remarks:] Uses `operator/=` to compose the returned path. + + + + +\[['Example:] + + + + +`assert(path("foo/./bar/..").lexically_normal() == "foo"); + +assert(path("foo/.///bar/../").lexically_normal() == "foo/.");` + + + + +The above assertions will succeed.[' ]On Windows, the +returned path's ['directory-separator] characters will be backslashes rather than slashes, but that +does not affect `path` equality.[' —end example]\] + + +] + + + + +``` +path [#lex-relative]lexically_relative(const path& base) const; +``` + + [: + + +['Overview:] Returns `*this` made relative to `base`. + Treats empty or identical paths as corner cases, not errors. Does not resolve + symlinks. Does not first normalize `*this` or `base`. + + + + + +['Remarks:] Uses `std::mismatch(begin(), end(), base.begin(), base.end())`, to determine the first mismatched element of + `*this` and `base`. Uses `operator==` to + determine if elements match. + + + + + +['Returns:] + + + + + * + `path()` if the first mismatched element of `*this` is equal to ` + begin()` or the first mismatched element + of `base` is equal to `base.begin()`, or +  + + * + `path(".")` if the first mismatched element of ` + *this` is equal to ` + end()` and the first mismatched element + of `base` is equal to `base.end()`, or +  + + * An object of class `path` composed via application of ` + operator/= path("..")` for each element in the half-open + range \[first + mismatched element of `base`, `base.end()`), and then + application of `operator/=` for each element in the half-open + range + \[first mismatched element of `*this`, `end()`). + + + + + +\[['Example:] + + + + +`assert(path("/a/d").lexically_relative("/a/b/c") == "../../d"); + +assert(path("/a/b/c").lexically_relative("/a/d") == "../b/c"); + +assert(path("a/b/c").lexically_relative("a") == "b/c"); + +assert(path("a/b/c").lexically_relative("a/b/c/x/y") == "../.."); + +assert(path("a/b/c").lexically_relative("a/b/c") == "."); + +assert(path("a/b").lexically_relative("c/d") == "");` + + + + +The above assertions will succeed.[' ]On Windows, the +returned path's ['directory-separator]s will be backslashes rather than +forward slashes, but that +does not affect `path` equality.[' —end example]\] + + + + + +\[['Note:] If symlink following semantics are desired, use the operational function ` + [@#op-proximate relative]`  ['—end note]\] + + + + + +\[['Note:] If [@#normal normalization] is needed to ensure + consistent matching of elements, apply `[@#normal lexically_normal()]` + to `*this`, `base`, or both. ['—end note]\] + + + +] + + + + + +``` +path [#lex-proximate]lexically_proximate(const path& base) const; +``` + + + [: + + + +['Returns:] If the value of `lexically_relative(base)` is + not an empty path, return it. Otherwise return `*this`. + + + + + +\[['Note:] If symlink following semantics are desired, use the operational function + `[@#op-proximate proximate]`  ['—end note]\] + + + + + +\[['Note:] If [@#normal normalization] is needed to ensure + consistent matching of elements, apply `[@#normal lexically_normal()]` + to `*this`, `base`, or both. ['—end note]\] + + + +] + + + + + +[h3 New [#operational-functions]operational functions] + + + + +[h4 [#Synopsis-ops]Synopsis] + + + + +``` +path weakly_canonical(const path& p); +path weakly_canonical(const path& p, system::error_code& ec); +path relative(const path& p, system::error_code& ec); +path relative(const path& p, const path& base=current_path()); +path relative(const path& p, const path& base, system::error_code& ec); +path proximate(const path& p, system::error_code& ec); +path proximate(const path& p, const path& base=current_path()); +path proximate(const path& p, const path& base, system::error_code& ec); + +``` + + +[h4 [#Specification-ops]Specification] + + + +``` +path [#weakly_canonical]weakly_canonical(const path& p); +path weakly_canonical(const path& p, system::error_code& ec); +``` + +[: +['Overview:] Returns `p` with symlinks resolved and the result +normalized. + + +['Returns: ] +A path composed of the result of calling the `canonical` function on +a path composed of the leading elements of `p` that exist, if any, +followed by the elements of `p` that do not exist, if any. + + + + +['Postcondition:] The returned path is in [@#normal normal form]. + + + + +['Remarks:] Uses `operator/=` to compose the returned path. +Uses the `status` function to determine existence. + + + + +['Remarks:] Implementations are encouraged to avoid unnecessary +normalization such as when `canonical` has already been called on the +entirety of `p`. + + + + +['Throws:]  As specified in Error reporting. + + +] + + + +``` +path [#op-relative]relative(const path& p, system::error_code& ec); +``` + +[: + + +['Returns:] `relative(p, current_path(), ec)`. + + + + +['Throws:]  As specified in Error reporting. + + + + ] + + + +``` +path relative(const path& p, const path& base=current_path()); +path relative(const path& p, const path& base, system::error_code& ec); +``` + +[: + + +['Overview:] Returns `p` made relative to ` + base`. Treats empty or identical paths as corner cases, not errors. + Resolves symlinks and normalizes both `p` and `base` + before other processing. + + + + + +['Returns:] `[@#weakly_canonical weakly_canonical](p).l[@#lex-proximate exically_relative]([@#weakly_canonical weakly_canonical](base))`. The second form returns `path()` if an error occurs. + + + + +['Throws:] As specified in Error reporting. + + +] + + + + +``` +path [#op-proximate]proximate(const path& p, system::error_code& ec); +``` + +[: + + +['Returns:] `proximate(p, current_path(), ec)`. + + + + +['Throws:]  As specified in Error reporting. + + + + ] + + + +``` +path proximate(const path& p, const path& base=current_path()); +path proximate(const path& p, const path& base, system::error_code& ec); +``` + +[: + + + +['Returns:] `[@#weakly_canonical weakly_canonical](p).l[@#lex-proximate exically_proximate]([@#weakly_canonical weakly_canonical](base))`. The second form returns `path()` if an error occurs. + + + + +['Throws:] As specified in Error reporting. + + +] + + + + + + +© Copyright Beman Dawes 2015 + + + + +Distributed under the Boost Software License, Version 1.0. See +[@http://www.boost.org/LICENSE_1_0.txt www.boost.org/LICENSE_1_0.txt] + + + diff --git a/doc/tutorial.qbk b/doc/tutorial.qbk new file mode 100644 index 000000000..dcfc3b015 --- /dev/null +++ b/doc/tutorial.qbk @@ -0,0 +1,835 @@ +[/ + / Copyright Andrey Semashev 2024. + / + / Distributed under the Boost Software License, Version 1.0. + / (See accompanying file LICENSE_1_0.txt or copy at + / https://www.boost.org/LICENSE_1_0.txt) + /] + +[section:tutorial Tutorial] + +[section:introduction Introduction] + +This tutorial develops a little command line program to list information about files and directories - essentially +a much simplified version of the POSIX `ls` or Windows `dir` commands. We'll start with the simplest possible version +and progress to more complex functionality. Along the way we'll digress to cover topics you'll need to know about +to understand Boost.Filesystem. + +Source code for each of the tutorial programs is available, and you are encouraged to compile, test, and experiment +with it. To conserve space, we won't always show boilerplate code here, but the provided source is complete and +ready to build. + +[endsect] + +[section:preliminaries Preliminaries] + +Install the Boost distribution if you haven't already done so. See the [link filesystem.install.building building +instructions]. + +This tutorial assumes you have bootstrapped Boost.Build and compiled Boost.Filesystem as described in the building +instructions. The `b2` executable is expected to be available in `PATH`. In the code samples below, ['[*boost-root]] +denotes the root directory of your Boost installation tree. + +Fire up your command line interpreter, and type the following commands: + +[table +[[Ubuntu Linux] [Microsoft Windows]] +[[ +[pre +$ cd ['[*boost-root]]\/libs\/filesystem\/example + +$ b2 tutorial +Compiling example programs... + +$ .\/tut1 +Usage: tut1 path +] +] +[ +[pre +>cd ['[*boost-root]]\\libs\\filesystem\\example + +>b2.exe tutorial +Compiling example programs... + +>tut1 +Usage: tut1 path +] +]] +] + +If the `tut1` command outputs "`Usage: tut1 path`", all is well. The tutorial example programs are available in +[^['[*boost-root]]\/libs\/filesystem\/example]. Should you modify and experiment with them as the tutorial progresses, +just invoke `b2 tutorial` again to rebuild. + +If something didn't work right, here are some troubleshooting suggestions: + +* If the `b2` program executable isn't being found, check your path environmental variable or see + [@https://www.boost.org/more/getting_started/windows.html Boost Getting Started]. +* Look at Boost bootstrap output to try to spot an indication of the problem. + +[endsect] + +[section:reporting-size Reporting the size of a file] + +Let's get started. Our first example program, [@../example/tut1.cpp `tut1.cpp`], reports the size of a file: + +[import ../example/tut1.cpp] +[example_tut1] + +The Boost.Filesystem [link filesystem.reference.file_size `file_size`] function returns a `uintmax_t` +containing the size of the file named by the argument. The declaration looks like this: + +``` +uintmax_t file_size(const path& p); +``` + +For now, all you need to know is that `class path` has constructors that take `const char *` and other +string types. (If you can't wait to find out more, skip ahead to the [link filesystem.tutorial.class-path-constructors class path] +section of the tutorial.) + +Please take a minute to try out `tut1` on your system, using a file that is known to exist, such as `tut1.cpp`. +Here is what the results look like on two different operating systems: + +[table +[[Ubuntu Linux] [Microsoft Windows]] +[[ +[pre +$ .\/tut1 tut1.cpp +tut1.cpp 569 + +$ ls -l tut1.cpp +-rw-rw-r-- 1 beman beman 569 Jul 26 12:04 tut1.cpp +] +] +[ +[pre +>tut1 tut1.cpp +tut1.cpp 592 + +>dir tut1.cpp +... +07\/26\/2015 07:20 AM 592 tut1.cpp +... +] +]] +] + +So far, so good. The reported Linux and Windows sizes are different because the Linux tests used "\\n" +line endings, while the Windows tests used "\\r\\n" line endings. The sizes reported may differ from +the above if changes have been made to `tut1.cpp`. + +Now try again, but give a path that doesn't exist: + +[table +[[Ubuntu Linux] [Microsoft Windows]] +[[ +[pre +$ .\/tut1 foo +terminate called after throwing an instance of 'boost::filesystem::filesystem_error' +what(): boost::filesystem::file_size: No such file or directory: "foo" +Aborted (core dumped) +] +] +[ +[pre +>tut1 foo +] + +['An exception is thrown; the exact form of the response depends on Windows system options.] +]] +] + +What happens? There's no file named `foo` in the current directory, so by default an exception +is thrown. See [link filesystem.tutorial.error-reporting Error reporting] to learn about error reporting +via error codes rather than exceptions. + +Try this: + +[table +[[Ubuntu Linux] [Microsoft Windows]] +[[ +[pre +$ .\/tut1 . +terminate called after throwing an instance of 'boost::filesystem::filesystem_error' +what(): boost::filesystem::file_size: Operation not permitted: "." +Aborted (core dumped) +] +] +[ +[pre +>tut1 . +] + +['An exception is thrown; the exact form of the response depends on Windows system options.] +]] +] + +The current directory exists, but `file_size()` works on regular files, not directories, so again +an exception is thrown. + +We'll deal with those situations in `tut2.cpp`. + +[endsect] + +[section:using-status-queries Using status queries to determine file existence and type] + +Boost.Filesystem includes status query functions such as [link filesystem.reference.exists-path `exists`], +[link filesystem.reference.is_directory-path `is_directory`], and [link filesystem.reference.is_regular_file-path `is_regular_file`]. +These return `bool`s, and will return `true` if the condition described by their name is met. Otherwise they +return `false`, including when any element of the path argument can't be found. + +[@../example/tut2.cpp `tut2.cpp`] uses several of the status query functions to cope with non-existent +files and with different kinds of files: + +[import ../example/tut2.cpp] +[example_tut2] + +Give it a try: + +[table +[[Ubuntu Linux] [Microsoft Windows]] +[[ +[pre +$ .\/tut2 tut2.cpp +"tut2.cpp" size is 997 + +$ .\/tut2 foo +"foo" does not exist + +$ .\/tut2 . +"." is a directory +] +] +[ +[pre +>tut2 tut2.cpp +tut2.cpp size is 1039 + +>tut2 foo +"foo" does not exist + +>tut2 . +"." is a directory +] +]] +] + +Although `tut2` works OK in these tests, the output is less than satisfactory for a directory. We'd typically +like to see a list of the directory's contents. In `tut3.cpp` we will see how to iterate over directories. + +But first, let's try one more test: + +[table +[[Ubuntu Linux] [Microsoft Windows]] +[[ +[pre +$ ls \/home\/jane\/foo +ls: cannot access \/home\/jane\/foo: No such file or directory + +$ .\/tut2 \/home\/jane\/foo +terminate called after throwing an instance of 'boost:: +filesystem::filesystem_error>' + what(): boost::filesystem::status: Permission denied: + "\/home\/jane\/foo" +Aborted +] +] +[ +[pre +>dir e:\\ +The device is not ready. + +>tut2 e:\\ +] + +['An exception is thrown; the exact form of the response depends on Windows system options.] +]] +] + +On the Linux system, the test was being run from an account that did not have permission to access +[^\/home\/jane\/foo]. On the Windows system, [^e:] was a Compact Disc reader\/writer that was not ready. End users +shouldn't have to interpret cryptic exceptions reports, so as we move on to `tut3.cpp` we will increase +the robustness of the code, too. + +[endsect] + +[section:directory-iteration Directory iteration plus catching exceptions] + +Boost.Filesystem's [link filesystem.reference.directory_iterator `directory_iterator`] class is just +what we need here. It follows the general pattern of the standard library's `istream_iterator`. Constructed +from a path, it iterates over the contents of the directory. A default constructed `directory_iterator` +acts as the end iterator. + +The value type of `directory_iterator` is [link filesystem.reference.directory_entry `directory_entry`]. +A `directory_entry` object contains `path` and [link filesystem.reference.file_status `file_status`] +information. A `directory_entry` object can be used directly, but can also be passed to `path` arguments +in function calls. + +The other need is increased robustness in the face of the many kinds of errors that can affect file system +operations. We could do that at the level of each call to a Boost.Filesystem function (see +[link filesystem.tutorial.error-reporting Error reporting]), but for simplicity [@../example/tut3.cpp +`tut3.cpp`] uses an overall `try`\/`catch` block. + +[import ../example/tut3.cpp] +[example_tut3] + +Give `tut3` a try, passing it a path to a directory as a command line argument. Here is a run on a checkout +of the Boost Git develop branch, followed by a repeat of the test cases that caused exceptions on Linux and +Windows: + +[table +[[Ubuntu Linux] [Microsoft Windows]] +[[ +[pre +$ .\/tut3 ~\/boost\/develop + "\/home\/beman\/boost\/develop" is a directory containing: + "\/home\/beman\/boost\/develop\/rst.css" + "\/home\/beman\/boost\/develop\/boost" + "\/home\/beman\/boost\/develop\/boost.png" + "\/home\/beman\/boost\/develop\/libs" + "\/home\/beman\/boost\/develop\/doc" + "\/home\/beman\/boost\/develop\/project-config.jam.2" + "\/home\/beman\/boost\/develop\/.gitmodules" + "\/home\/beman\/boost\/develop\/boostcpp.py" + "\/home\/beman\/boost\/develop\/.travis.yml" + "\/home\/beman\/boost\/develop\/.gitattributes" + "\/home\/beman\/boost\/develop\/index.htm" + "\/home\/beman\/boost\/develop\/index.html" + "\/home\/beman\/boost\/develop\/bjam" + "\/home\/beman\/boost\/develop\/project-config.jam.1" + "\/home\/beman\/boost\/develop\/LICENSE_1_0.txt" + "\/home\/beman\/boost\/develop\/.git" + "\/home\/beman\/boost\/develop\/tools" + "\/home\/beman\/boost\/develop\/stage" + "\/home\/beman\/boost\/develop\/boostcpp.jam" + "\/home\/beman\/boost\/develop\/Jamroot" + "\/home\/beman\/boost\/develop\/.gitignore" + "\/home\/beman\/boost\/develop\/INSTALL" + "\/home\/beman\/boost\/develop\/more" + "\/home\/beman\/boost\/develop\/bin.v2" + "\/home\/beman\/boost\/develop\/project-config.jam" + "\/home\/beman\/boost\/develop\/boost-build.jam" + "\/home\/beman\/boost\/develop\/bootstrap.bat" + "\/home\/beman\/boost\/develop\/bootstrap.sh" + "\/home\/beman\/boost\/develop\/status" + "\/home\/beman\/boost\/develop\/boost.css" + +$ .\/tut3 \/home\/jane\/foo +boost::filesystem::status: Permission denied: "\/home\/jane\/foo" +] +] +[ +[pre +>tut3 \\boost\\develop +"\\boost\\develop" is a directory containing: + "\\boost\\develop\\.git" + "\\boost\\develop\\.gitattributes" + "\\boost\\develop\\.gitignore" + "\\boost\\develop\\.gitmodules" + "\\boost\\develop\\.travis.yml" + "\\boost\\develop\\bin.v2" + "\\boost\\develop\\boost" + "\\boost\\develop\\boost-build.jam" + "\\boost\\develop\\boost.css" + "\\boost\\develop\\boost.png" + "\\boost\\develop\\boostcpp.jam" + "\\boost\\develop\\boostcpp.py" + "\\boost\\develop\\bootstrap.bat" + "\\boost\\develop\\bootstrap.sh" + "\\boost\\develop\\doc" + "\\boost\\develop\\index.htm" + "\\boost\\develop\\index.html" + "\\boost\\develop\\INSTALL" + "\\boost\\develop\\Jamroot" + "\\boost\\develop\\libs" + "\\boost\\develop\\LICENSE_1_0.txt" + "\\boost\\develop\\more" + "\\boost\\develop\\project-config.jam" + "\\boost\\develop\\rst.css" + "\\boost\\develop\\stage" + "\\boost\\develop\\status" + "\\boost\\develop\\tools" + +>tut3 e:\\ +boost::filesystem::status: The device is not ready: "e:\\" +] +]] +] + +Not bad, but we can make further improvements: + +* The listing would be much easier to read if only the filename was displayed, rather than the full path. +* The Linux listing isn't sorted. That's because the ordering of directory iteration is unspecified. + Ordering depends on the underlying operating system API and file system specifics. So we need to sort the + results ourselves. + +The next sections show how those changes play out, so read on! + +[endsect] + +[section:using-path-decomposition Using path decomposition, plus sorting results] + +For directories, [@../example/tut4.cpp `tut4.cpp`] builds a `std::vector` of all the entries and then sorts +it before writing to `std::cout`. + +[import ../example/tut4.cpp] +[example_tut4] + +The only difference between `tut3.cpp` and `tut4.cpp` is what happens for directories. We changed: + +``` +for (directory_entry const& x : directory_iterator(p)) + std::cout << " " << x.path() << std::endl; +``` + +to: + +``` +std::vector v; + +for (auto&& x : directory_iterator(p)) + v.push_back(x.path()); + +std::sort(v.begin(), v.end()); + +for (auto&& x : v) + std::cout << " " << x.filename() << std::endl; +``` + +[link filesystem.reference.path-filename `filename()`] is one of several class `path` decomposition +functions. It extracts the filename portion from a path (i.e. [^"index.html"] from [^"\/home\/beman\/boost\/trunk\/index.html"]). +These decomposition functions are more fully explored in the [link filesystem.tutorial.path-iterators-etc Path iterators, +observers, composition, decomposition and query] portion of this tutorial. + +The above was written as two lines of code for clarity. It could have been written more concisely as: + +``` +v.push_back(it->path().filename()); // we only care about the filename +``` + +Here is the output from a test of [@../example/tut4.cpp `tut4.cpp`]: + +[table +[[Ubuntu Linux] [Microsoft Windows]] +[[ +[pre +$ .\/tut4 ~\/boost\/develop +"\/home\/beman\/boost\/develop" is a directory containing: + ".git" + ".gitattributes" + ".gitignore" + ".gitmodules" + ".travis.yml" + "INSTALL" + "Jamroot" + "LICENSE_1_0.txt" + "bin.v2" + "boost" + "boost-build.jam" + "boost.css" + "boost.png" + "boostcpp.jam" + "boostcpp.py" + "bootstrap.bat" + "bootstrap.sh" + "doc" + "index.htm" + "index.html" + "libs" + "more" + "project-config.jam" + "project-config.jam.1" + "project-config.jam.2" + "rst.css" + "stage" + "status" + "tools" +] +] +[ +[pre +>tut4 \\boost\\develop +"\\boost\\develop" is a directory containing: + ".git" + ".gitattributes" + ".gitignore" + ".gitmodules" + ".travis.yml" + "INSTALL" + "Jamroot" + "LICENSE_1_0.txt" + "bin.v2" + "boost" + "boost-build.jam" + "boost.css" + "boost.png" + "boostcpp.jam" + "boostcpp.py" + "bootstrap.bat" + "bootstrap.sh" + "doc" + "index.htm" + "index.html" + "libs" + "more" + "project-config.jam" + "project-config.jam.1" + "project-config.jam.2" + "rst.css" + "stage" + "status" + "tools" +] +]] +] + +That completes the main portion of this tutorial. If you haven't already worked through the +[link filesystem.tutorial.class-path-constructors Class path] sections of this tutorial, dig into them now. +The [link filesystem.tutorial.error-reporting Error reporting] section may also be of interest, although it can be +skipped unless you are deeply concerned about error handling issues. + +[endsect] + +[section:class-path-constructors Class path: Constructors, including Unicode] + +Traditional C interfaces pass paths as `const char*` arguments. C++ interfaces may add `const std::string&` overloads, +but adding overloads becomes untenable if wide characters, containers, and iterator ranges need to be supported. + +Passing paths as `const path&` arguments is far simpler, yet far more flexible because class `path` itself is far more flexible: + +# Class `path` supports multiple character types and encodings, including Unicode, to ease internationalization. +# Class `path` supports multiple source types, such as null terminated character sequences, iterator ranges, string class types + (including `std::basic_string` and `std::basic_string_view`), and [link filesystem.reference.class-directory_entry + `directory_entry`]s, so functions taking paths don't need to provide several overloads. +# Class `path` supports both native and generic pathname formats, so programs can be portable between operating systems + yet use native formats where desirable. +# Class `path` supplies a full set of iterators, observers, composition, decomposition, and query functions, making pathname + manipulations easy, convenient, reliable, and portable. + +Here is how (1) and (2) work. Class path constructors, assignments, and appends have member templates for sources. For example, +here are the constructors that take sources: + +``` +template +path(Source const& source); + +template +path(InputIterator begin, InputIterator end); +``` + +Let's look at [@../example/tut5.cpp `tut5.cpp`] sample program that shows how comfortable class `path` is with both narrow +and wide characters in C-style strings, C++ strings, and via C++ iterators: + +[import ../example/tut5.cpp] +[example_tut5] + +Testing `tut5`: + +[table +[[Ubuntu Linux] [Microsoft Windows]] +[[ +[pre +$ .\/tut5 + +$ ls smile* +smile smile☺ smile2 smile2☺ smile3 smile3☺ smile4 smile4☺ +] +] +[ +[pre +>tut5 + +>dir \/b smile* +smile +smile2 +smile2☺ +smile3 +smile3☺ +smile4 +smile4☺ +smile☺ +] +]] +] + +The exact appearance of the smiling face will depend on the font, font size, and other settings for your command line +window. The above tests were run with out-of-the-box Ubuntu 14.04 and Windows 7, US Edition. If you don't get the above +results, take a look at the [^['[*boost-root]]\/libs\/filesystem\/example] directory with your system's GUI file browser, +such as Linux Nautilus, Mac OS X Finder, or Windows Explorer. These tend to be more comfortable with international +character sets than command line interpreters. + +Class `path` takes care of whatever character type or encoding conversions are required by the particular operating system. +Thus as `tut5` demonstrates, it's no problem to pass a wide character string to a Boost.Filesystem operational function +even if the underlying operating system uses narrow characters, and visa versa. And the same applies to user supplied +functions that take `const path&` arguments. + +Class `path` also provides path syntax that is portable across operating systems, element iterators, and observer, +composition, decomposition, and query functions to manipulate the elements of a path. The next section of this +tutorial deals with path syntax. + +[endsect] + +[section:class-path-formats Class path: Generic format vs. Native format] + +Class `path` deals with two different pathname formats - generic format and native format. For POSIX-like file systems, +these formats are the same. But for users of Windows and other non-POSIX file systems, the distinction is important. Even +programmers writing for POSIX-like systems need to understand the distinction if they want their code to be portable +to non-POSIX systems. + +The [*generic format] is the familiar [^\/my_directory\/my_file.txt] format used by POSIX-like operating systems such as +the Unix variants, Linux, and Mac OS X. Windows also recognizes the generic format, and it is the basis for the familiar +Internet URL format. The directory separator character is always one or more slash characters. + +The [*native format] is the format as defined by the particular operating system. For Windows, either the slash or +the backslash can be used as the directory separator character, so [^\/my_directory\\\\my_file.txt] would work fine. Of +course, if you write that in a C++ string literal, it becomes `"/my_directory\\\\my_file.txt"`. + +If a drive specifier or a backslash appears in a pathname on a Windows system, it is always treated as the native format. + +Class `path` has observer functions that allow you to obtain the string representation of a path object in either the native +format or the generic format. See the [link filesystem.tutorial.path-iterators-etc next section] for how that plays out. + +The distinction between generic format and native format is important when communicating with native C-style API's and +with users. Both tend to expect paths in the native format and may be confused by the generic format. The generic format +is great, however, for writing portable programs that work regardless of operating system. + +The next section covers class `path` observers, composition, decomposition, query, and iteration over the elements of a path. + +[endsect] + +[section:path-iterators-etc Class path: Iterators, observers, composition, decomposition, and query] + +The [@../example/path_info.cpp `path_info.cpp`] program is handy for learning how class `path` iterators, observers, +composition, decomposition, and query functions work on your system. + +[import ../example/path_info.cpp] +[example_path_info] + +Run the examples below on your system, and try some different path arguments as we go along. Here is the invocation +we will talk about in detail: + +[table +[[Ubuntu Linux] [Microsoft Windows]] +[[ +[pre +$ .\/path_info \/foo bar baa.txt + +composed path: + operator<<()---------: "\/foo\/bar\/baa.txt" + make_preferred()-----: "\/foo\/bar\/baa.txt" + +elements: + "\/" + "foo" + "bar" + "baa.txt" + +observers, native format: + native()-------------: \/foo\/bar\/baa.txt + c_str()--------------: \/foo\/bar\/baa.txt + string()-------------: \/foo\/bar\/baa.txt + wstring()------------: \/foo\/bar\/baa.txt + +observers, generic format: + generic_string()-----: \/foo\/bar\/baa.txt + generic_wstring()----: \/foo\/bar\/baa.txt + +decomposition: + root_name()----------: "" + root_directory()-----: "\/" + root_path()----------: "\/" + relative_path()------: "foo\/bar\/baa.txt" + parent_path()--------: "\/foo\/bar" + filename()-----------: "baa.txt" + stem()---------------: "baa" + extension()----------: ".txt" + +query: + empty()--------------: false + is_absolute()--------: true + has_root_name()------: false + has_root_directory()-: true + has_root_path()------: true + has_relative_path()--: true + has_parent_path()----: true + has_filename()-------: true + has_stem()-----------: true + has_extension()------: true +] +] +[ +[pre +>path_info \\foo bar baa.txt + +composed path: +operator<<()---------: "\\foo\\bar\\baa.txt" +make_preferred()-----: "\\foo\\bar\\baa.txt" + +elements: + "\/" + "foo" + "bar" + "baa.txt" + +observers, native format: +native()-------------: \\foo\\bar\\baa.txt +c_str()--------------: \\foo\\bar\\baa.txt +string()-------------: \\foo\\bar\\baa.txt +wstring()------------: \\foo\\bar\\baa.txt + +observers, generic format: +generic_string()-----: \/foo\/bar\/baa.txt +generic_wstring()----: \/foo\/bar\/baa.txt + +decomposition: +root_name()----------: "" +root_directory()-----: "\\" +root_path()----------: "\\" +relative_path()------: "foo\\bar\\baa.txt" +parent_path()--------: "\\foo\\bar" +filename()-----------: "baa.txt" +stem()---------------: "baa" +extension()----------: ".txt" + +query: +empty()--------------: false +is_absolute()--------: false +has_root_name()------: false +has_root_directory()-: true +has_root_path()------: true +has_relative_path()--: true +has_parent_path()----: true +has_filename()-------: true +has_stem()-----------: true +has_extension()------: true +] +]] +] + +We will go through the above code in detail to gain a better understanding of what is going on. + +A common need is to compose a path from its constituent directories. Class `path` uses `/` and `/=` operators to +append elements. That's a reminder that these operations append the operating system's preferred directory +separator if needed. The preferred directory separator is a slash on POSIX-like systems, and a backslash on +Windows-like systems. + +That's what this code does before displaying the resulting `path p` using the `class path` stream inserter: + +``` +path p; +for (int i = 1; i < argc; ++i) + p /= argv[i]; // compose path p from the command line arguments + +std::cout << "\ncomposed path:" << std::endl; +std::cout << " operator<<()---------: " << p << std::endl; +std::cout << " make_preferred()-----: " << p.make_preferred() << std::endl; +``` + +One abstraction for thinking about a path is as a sequence of elements, where the elements are directory and +file names. To support this abstraction, class `path` provides iterators and also `begin()` and `end()` functions. + +Here is the code that produced the list of elements in the above output listing: + +``` +std::cout << "\nelements:" << std::endl; +for (auto element : p) + std::cout << " " << element << std::endl; +``` + +Let's look at class path observer functions: + +``` +std::cout << "\nobservers, native format:" << std::endl; +#ifdef BOOST_POSIX_API +std::cout << " native()-------------: " << p.native() << std::endl; +std::cout << " c_str()--------------: " << p.c_str() << std::endl; +#else // BOOST_WINDOWS_API +std::wcout << L" native()-------------: " << p.native() << std::endl; +std::wcout << L" c_str()--------------: " << p.c_str() << std::endl; +#endif +std::cout << " string()-------------: " << p.string() << std::endl; +std::wcout << L" wstring()------------: " << p.wstring() << std::endl; + +std::cout << "\nobservers, generic format:" << std::endl; +std::cout << " generic_string()-----: " << p.generic_string() << std::endl; +std::wcout << L" generic_wstring()----: " << p.generic_wstring() << std::endl; +``` + +Native format observers should be used when interacting with the operating system or with users; that's what +they expect. + +Generic format observers should be used when the results need to be portable and uniform regardless of +the operating system. + +`path` objects always hold pathnames in the native format, but otherwise leave them unchanged from their source. +The [link filesystem.reference.preferred `preferred()`] function will convert to the preferred form, if the native +format has several forms. Thus on Windows, it will convert slashes to backslashes. + +Moving on to decomposition: + +``` +std::cout << "\ndecomposition:" << std::endl; +std::cout << " root_name()----------: " << p.root_name() << std::endl; +std::cout << " root_directory()-----: " << p.root_directory() << std::endl; +std::cout << " root_path()----------: " << p.root_path() << std::endl; +std::cout << " relative_path()------: " << p.relative_path() << std::endl; +std::cout << " parent_path()--------: " << p.parent_path() << std::endl; +std::cout << " filename()-----------: " << p.filename() << std::endl; +std::cout << " stem()---------------: " << p.stem() << std::endl; +std::cout << " extension()----------: " << p.extension() << std::endl; +``` + +And, finally, query functions: + +``` +std::cout << "\nquery:" << std::endl; +std::cout << " empty()--------------: " << p.empty() << std::endl; +std::cout << " is_absolute()--------: " << p.is_absolute() << std::endl; +std::cout << " has_root_name()------: " << p.has_root_name() << std::endl; +std::cout << " has_root_directory()-: " << p.has_root_directory() << std::endl; +std::cout << " has_root_path()------: " << p.has_root_path() << std::endl; +std::cout << " has_relative_path()--: " << p.has_relative_path() << std::endl; +std::cout << " has_parent_path()----: " << p.has_parent_path() << std::endl; +std::cout << " has_filename()-------: " << p.has_filename() << std::endl; +std::cout << " has_stem()-----------: " << p.has_stem() << std::endl; +std::cout << " has_extension()------: " << p.has_extension() << std::endl; +``` + +These are pretty self-evident, but do note the difference in the result of `is_absolute()` between Linux and Windows. +Because there is no root name (i.e. drive specifier or network name), a lone slash (or backslash) is a relative path +on Windows but an absolute path on POSIX-like operating systems. + +[endsect] + +[section:error-reporting Error reporting] + +The Boost.Filesystem `file_size` function, like many of the operational functions, has two overloads: + +``` +uintmax_t file_size(const path& p); +uintmax_t file_size(const path& p, system::error_code& ec); +``` + +The only significant difference between the two is how they report errors. + +The first signature will throw exceptions to report errors. A [link filesystem.reference.class-filesystem_error +`filesystem_error`] exception will be thrown on an operational error. `filesystem_error` is derived from +`std::runtime_error`. It has a member function to obtain the `error_code` (defined in __boost_system__) reported by +the source of the error. It also has member functions to obtain the path or paths that caused the error. + +[blurb [*Motivation for the second signature:] + +Throwing exceptions on errors was the entire error reporting story for the earliest versions of Boost.Filesystem, +and indeed throwing exceptions on errors works very well for many applications. But user reports trickled in that +some code became so littered with try and catch blocks as to be unreadable and unmaintainable. In some applications +I/O errors aren't exceptional, and that's the use case for the second signature. +] + +Functions with a `system::error_code&` argument set that argument to report operational error status, and so do not +throw exceptions when I\/O related errors occur. For a full explanation, see [link filesystem.reference.error-reporting +Error reporting] in the reference documentation. + +[endsect] + +[endsect] diff --git a/doc/v3.qbk b/doc/v3.qbk new file mode 100644 index 000000000..b032f9ae7 --- /dev/null +++ b/doc/v3.qbk @@ -0,0 +1,197 @@ +[/ + / Copyright Andrey Semashev 2024. + / + / Distributed under the Boost Software License, Version 1.0. + / (See accompanying file LICENSE_1_0.txt or copy at + / http://www.boost.org/LICENSE_1_0.txt) + /] + +[section:v3 Boost Filesystem Version 3] + +Version 3 is a major revision of the Boost Filesystem library. Important changes include: + +* A single class `path` handles all aspects of internationalization, replacing the previous template and its `path` and `wpath` + instantiations. Character types `char` and `wchar_t` are supported. This is a major simplification of the path abstraction, + particularly for functions that take path arguments. +* New `class path` members include: + * [link filesystem.reference.path-has_stem `has_stem()`] + * [link filesystem.reference.path-has_extension `has_extension()`] + * [link filesystem.reference.path-is_absolute `is_absolute()`]. This renames `is_complete()`, which is now deprecated. + * [link filesystem.reference.path-is_relative `is_relative()`] + * [link filesystem.reference.path-make_preferred `make_preferred()`] +* New or improved operations functions include: + * [link filesystem.reference.absolute `absolute()`]. This replaces the operations function `complete()`, which is now + deprecated. Semantics are now provided for a Windows corner case where the `base` argument was not an absolute path. + Previously this resulted in an exception being thrown. + * [link filesystem.reference.create_symlink `create_symlink()`] now supported on both POSIX and Windows. + * [link filesystem.reference.read_symlink `read_symlink()`] function added. Supported on both POSIX and Windows. Used + to read the contents of a symlink itself. + * [link filesystem.reference.resize_file `resize_file()`] function added. Supported on both POSIX and Windows. Used to shrink + or grow a regular file. + * [link filesystem.reference.unique_path `unique_path()`] function added. Supported on both POSIX and Windows. Used to generate + a secure temporary pathname. +* Support for error reporting via `error_code` is now uniform throughout the operation functions. +* Documentation has been reworked, including re-writes of major portions. +* A new [link filesystem.tutorial Tutorial] provides a hopefully much gentler and more complete introduction for new users. + Current users might want to review the three sections related to class path. + +[section:deprecated Deprecated names and other features] + +See the [link filesystem.deprecated Deprecated Features page] for transition aids that allow much existing code to compile +without change using Version 3. + +[endsect] + +[section:breaking_changes Breaking changes] + +To ease the transition, Versions 2 and 3 both used to be included in the next several Boost releases. Version 2 was removed in +Boost 1.50.0. + +[section:path Class `path`] + +* Class template `basic_path` and its specializations are replaced by a single class `path`. Thus any code, such as overloaded + functions, that depend on `path` and `wpath` being two distinct types will fail to compile and must be restructured. + Restructuring may be as simple as removing one of the overloads, but also might require more complex redesign. +* Certain functions now return `path` objects rather than `string` or `wstring` objects: + * `root_name()` + * `root_directory()` + * `filename()` + * `stem()` + * `extension()` + Not all uses will fail; if the function is being called in a context that accepts a `path`, all is well. If the result is being + used in a context requiring a `std::string` or `std::wstring`, then `.string()` or `.wstring()` respectively must be appended + to the function call. +* `path::iterator::value_type` and `path::const_iterator::value_type` is `path` rather than `std::basic_string`. + +[endsect] + +[section:compilers Compiler support] + +* Compilers and standard libraries that do not fully support wide characters and wide character strings (`std::wstring`) are + no longer supported. +* Cygwin versions prior to 1.7 are no longer supported because they lack wide string support. Cygwin now compiles only for + the Windows API and path syntax. +* MinGW versions not supporting wide strings are no longer supported. +* Microsoft VC++ 7.1 and earlier are no longer supported. + +[endsect] + +[endsect] + +[section:design Design] + +[warning This section documents thinking early in the V3 development process, and is intended to serve historical purposes. +It is not updated to reflect the current state of the library.] + +[note Some parts of the discussion in this section are spoken from the perspective of the original author of Boost.Filesystem, +Beman Dawes. This text is preserved, with minor editorial and formatting changes, for historical reasons.] + +[section:introduction Introduction] + +During the review of Boost.Filesystem.V2 (Internationalization), Peter Dimov suggested that the `basic_path` class template +was unwieldy, and that a single path type that accommodated multiple character types and encodings would be more flexible. Although +I wasn't willing to stop development at that time to explore how this idea might be implemented, or to break from the pattern for +Internationalization used the C++ standard library, I've often thought about Peter's suggestion. With the advent of C++0x `char16_t` +and `char32_t` character types, the `basic_path` class template approach becomes even more unwieldy, so it is time to revisit +the problem in light of Peter's suggestion. + +[endsect] + +[section:problem Problem] + +With Filesystem.V2, a path argument to a user defined function that is to accommodate multiple character types and encodings must +be written as a template. Do-the-right-thing overloads or template metaprogramming must be employed to allow arguments to be written +as string literals. Here's what it looks like: + +``` +template +void foo(const Path& p); + +inline void foo(const path& p) +{ + foo(p); +} + +inline void foo(const wpath& p) +{ + foo(p); +} +``` + +That's really ugly for such a simple need, and there would be a combinatorial explosion if the function took multiple `Path` +arguments and each could be either narrow or wide. It gets even worse if the C++0x `char16_t` and `char32_t` types are to be +supported. + +[endsect] + +[section:solution Solution] + +Overview: + +* A single, non-template, class `path`. +* Each member function is a template accommodating the various applicable character types, including user-defined character types. +* Hold the path internally in a string of the type used by the operating system API; `std::string` for POSIX, `std::wstring` for + Windows. + +The signatures presented in [link filesystem.v3.design.problem Problem] collapse to simply: + +``` +void foo(const path& p); +``` + +That's a significant reduction in code complexity. Specification becomes simpler, too. I believe it will be far easier to teach, +and result in much more flexible user code. + +Other benefits: + +* All the polymorphism still occurs at compile time. +* Efficiency is increased, in that conversions of the encoding, if required, only occur once at the time of creation, not each time + the path is used. +* The size of the implementation code drops approximately in half and becomes much more readable. + +Possible problems: + +* The combination of member function templates and implicit constructors can result in unclear error messages when the user makes + simple commonplace coding errors. This should be much less of a problem with C++ concepts, but in the meantime work continues + to restrict over aggressive templates via `enable_if`/`disable_if`. + +[endsect] + +[section:details Details] + +[table Encoding Conversions +[[Host system] [char string path arguments] [wide string path arguments]] +[[ +Systems with `char` as the native API path character type (i.e. POSIX-like systems) +] +[ +No conversion. +] +[ +Conversion occurs, performed by the current path locale's `codecvt` facet. +]] +[[ +Systems with `wchar_t` as the native API path character type (i.e. Windows-like systems). +] +[ +Conversion occurs, performed by the current path locale's `codecvt` facet. +] +[ +No conversion. +]] +] + +When a class `path` function argument type matches the operating system's API argument type for paths, no conversion is performed +rather than conversion to a specified encoding such as one of the Unicode encodings. This avoids unintended consequences, etc. + +[endsect] + +[section:other-changes Other changes] + +* Uniform hybrid error handling: The hybrid error handling idiom has been consistently applied to all applicable functions. + +[endsect] + +[endsect] + +[endsect] diff --git a/doc/v4.qbk b/doc/v4.qbk new file mode 100644 index 000000000..9112d8b20 --- /dev/null +++ b/doc/v4.qbk @@ -0,0 +1,71 @@ +[/ + / Copyright Andrey Semashev 2024. + / + / Distributed under the Boost Software License, Version 1.0. + / (See accompanying file LICENSE_1_0.txt or copy at + / http://www.boost.org/LICENSE_1_0.txt) + /] + +[section:v4 Boost Filesystem Version 4] + +Version 4 is a significant revision of the Boost Filesystem library that makes its interface and behavior closer to std::filesystem +that was introduced in C++17 and updated in the later standards. It removes the features that were [link filesystem.deprecated +deprecated] in Version 3 and makes a number of breaking changes. Eventually, Version 4 will become the default, and Version 3 will +be removed. + +Users can select Boost.Filesystem v4 version by defining `BOOST_FILESYSTEM_VERSION` macro to 4 when compiling their code. There +is no need to separately compile Boost.Filesystem for each library version — a single binary supports both v3 and v4. Users +should avoid using both v3 and v4 in the same application as this can lead to subtle bugs. + +[section:breaking_changes Breaking changes] + +[section:path Class `path` behavior] + +* [link filesystem.reference.path-filename `path::filename`] no longer returns root name or root directory if the path contains no + other elements. For example, on Windows `path("C:").filename()` used to return "C:" and `path("C:\\").filename()` used to return + "\\" and both will return an empty path now. This also affects `path::stem` and `path::extension` methods, as those are based on + `path::filename`. +* [link filesystem.reference.path-stem `path::stem`] and [link filesystem.reference.path-extension `path::extension`] no longer + treat a filename that starts with a dot and has no other dots as an extension. Filenames starting with a dot are commonly treated + as filenames with an empty extension. The leading dot is used to indicate a hidden file on most UNIX-like systems. +* [link filesystem.reference.path-filename `path::filename`] and [link filesystem.reference.path-iterators `path::iterator`] + no longer return an implicit trailing dot (".") element if the path ends with a directory separator. Instead, an empty path + is returned, similar to C++17 std::filesystem. This also affects other methods that are defined in terms of iterators or filename, + such as `path::stem`, `path::compare` or `lexicographical_compare`. For example, `path("a/b/") == path("a/b/.")` no longer holds + true. +* [link filesystem.reference.lexically_normal `path::lexically_normal`] no longer produces a trailing dot (".") element and omits + a directory separator after a trailing dot-dot ("..") element in the normalized paths. +* [link filesystem.reference.lexically_normal `path::lexically_normal`], [link filesystem.reference.path-make_preferred + `path::make_preferred`], [link filesystem.reference.path-generic-format-observers `path::generic_string`] and similar methods + no longer convert between forward and backward slashes in root names of the returned paths. +* [link filesystem.reference.path-appends `path` appends] consider root name and root directory of the appended path. If the appended + path is absolute, or root name is present and differs from the source path, the resulting path is equivalent to the appended path. + If root directory is present, the result is the root directory and relative path rebased on top of the root name of the source + path. Otherwise, the behavior is similar to v3. This behavior is similar to C++17 std::filesystem. +* `path` no longer supports construction, assignment or appending from containers of characters. Use string types or iterators as + the source for these opereations instead. +* [link filesystem.reference.path-remove_filename `path::remove_filename`] preserves the trailing directory separator, so that + `path::has_filename` returns `false` after a successful call to `path::remove_filename`. + +[endsect] + +[section:directory Directory operations] + +* `directory_entry` constructors and modifiers that initialize or modify path of the directory entry automatically call + `directory_entry::refresh` instead of clearing cached file statuses. This means that the file identified by the new path needs + to be accessible in the filesystem at the point of the call. +* `directory_entry` constructors and modifiers that accept `file_status` arguments to initialize cached file statuses are removed. + The amount of cached data is an implementation detail of `directory_entry`, and in the future it may not be limited to just file + statuses. Users should rely on automatic refreshes of the cached data. + +[endsect] + +[section:operations Filesystem operations] + +* [link filesystem.reference.equivalent `equivalent`] now fails if only one of the input paths exists. + +[endsect] + +[endsect] + +[endsect] diff --git a/example/path_info.cpp b/example/path_info.cpp index 0f2ed67cb..14b13f142 100644 --- a/example/path_info.cpp +++ b/example/path_info.cpp @@ -7,80 +7,81 @@ // Library home page: http://www.boost.org/libs/filesystem +//[example_path_info +#include #include #include -using namespace std; using namespace boost::filesystem; -const char* say_what(bool b) -{ - return b ? "true" : "false"; -} - int main(int argc, char* argv[]) { if (argc < 2) { - cout << "Usage: path_info path-element [path-element...]\n" + std::cout << "Usage: path_info path-element [path-element...]\n" "Composes a path via operator/= from one or more path-element arguments\n" "Example: path_info foo/bar baz\n" + " would report info about the composed path " #ifdef BOOST_POSIX_API - " would report info about the composed path foo/bar/baz\n"; + "foo/bar/baz" #else // BOOST_WINDOWS_API - " would report info about the composed path foo/bar\\baz\n"; + "foo/bar\\baz" #endif + << std::endl; return 1; } path p; - for (; argc > 1; --argc, ++argv) - p /= argv[1]; // compose path p from the command line arguments + for (int i = 1; i < argc; ++i) + p /= argv[i]; // compose path p from the command line arguments - cout << "\ncomposed path:\n"; - cout << " operator<<()---------: " << p << "\n"; - cout << " make_preferred()-----: " << p.make_preferred() << "\n"; + std::cout << "\ncomposed path:" << std::endl; + std::cout << " operator<<()---------: " << p << std::endl; + std::cout << " make_preferred()-----: " << p.make_preferred() << std::endl; - cout << "\nelements:\n"; + std::cout << "\nelements:" << std::endl; for (auto element : p) - cout << " " << element << '\n'; + std::cout << " " << element << std::endl; - cout << "\nobservers, native format:" << endl; + std::cout << "\nobservers, native format:" << std::endl; #ifdef BOOST_POSIX_API - cout << " native()-------------: " << p.native() << endl; - cout << " c_str()--------------: " << p.c_str() << endl; + std::cout << " native()-------------: " << p.native() << std::endl; + std::cout << " c_str()--------------: " << p.c_str() << std::endl; #else // BOOST_WINDOWS_API - wcout << L" native()-------------: " << p.native() << endl; - wcout << L" c_str()--------------: " << p.c_str() << endl; + std::wcout << L" native()-------------: " << p.native() << std::endl; + std::wcout << L" c_str()--------------: " << p.c_str() << std::endl; #endif - cout << " string()-------------: " << p.string() << endl; - wcout << L" wstring()------------: " << p.wstring() << endl; + std::cout << " string()-------------: " << p.string() << std::endl; + std::wcout << L" wstring()------------: " << p.wstring() << std::endl; + + std::cout << "\nobservers, generic format:" << std::endl; + std::cout << " generic_string()-----: " << p.generic_string() << std::endl; + std::wcout << L" generic_wstring()----: " << p.generic_wstring() << std::endl; - cout << "\nobservers, generic format:\n"; - cout << " generic_string()-----: " << p.generic_string() << endl; - wcout << L" generic_wstring()----: " << p.generic_wstring() << endl; + std::cout << "\ndecomposition:" << std::endl; + std::cout << " root_name()----------: " << p.root_name() << std::endl; + std::cout << " root_directory()-----: " << p.root_directory() << std::endl; + std::cout << " root_path()----------: " << p.root_path() << std::endl; + std::cout << " relative_path()------: " << p.relative_path() << std::endl; + std::cout << " parent_path()--------: " << p.parent_path() << std::endl; + std::cout << " filename()-----------: " << p.filename() << std::endl; + std::cout << " stem()---------------: " << p.stem() << std::endl; + std::cout << " extension()----------: " << p.extension() << std::endl; - cout << "\ndecomposition:\n"; - cout << " root_name()----------: " << p.root_name() << '\n'; - cout << " root_directory()-----: " << p.root_directory() << '\n'; - cout << " root_path()----------: " << p.root_path() << '\n'; - cout << " relative_path()------: " << p.relative_path() << '\n'; - cout << " parent_path()--------: " << p.parent_path() << '\n'; - cout << " filename()-----------: " << p.filename() << '\n'; - cout << " stem()---------------: " << p.stem() << '\n'; - cout << " extension()----------: " << p.extension() << '\n'; + std::cout << std::boolalpha; - cout << "\nquery:\n"; - cout << " empty()--------------: " << say_what(p.empty()) << '\n'; - cout << " is_absolute()--------: " << say_what(p.is_absolute()) << '\n'; - cout << " has_root_name()------: " << say_what(p.has_root_name()) << '\n'; - cout << " has_root_directory()-: " << say_what(p.has_root_directory()) << '\n'; - cout << " has_root_path()------: " << say_what(p.has_root_path()) << '\n'; - cout << " has_relative_path()--: " << say_what(p.has_relative_path()) << '\n'; - cout << " has_parent_path()----: " << say_what(p.has_parent_path()) << '\n'; - cout << " has_filename()-------: " << say_what(p.has_filename()) << '\n'; - cout << " has_stem()-----------: " << say_what(p.has_stem()) << '\n'; - cout << " has_extension()------: " << say_what(p.has_extension()) << '\n'; + std::cout << "\nquery:" << std::endl; + std::cout << " empty()--------------: " << p.empty() << std::endl; + std::cout << " is_absolute()--------: " << p.is_absolute() << std::endl; + std::cout << " has_root_name()------: " << p.has_root_name() << std::endl; + std::cout << " has_root_directory()-: " << p.has_root_directory() << std::endl; + std::cout << " has_root_path()------: " << p.has_root_path() << std::endl; + std::cout << " has_relative_path()--: " << p.has_relative_path() << std::endl; + std::cout << " has_parent_path()----: " << p.has_parent_path() << std::endl; + std::cout << " has_filename()-------: " << p.has_filename() << std::endl; + std::cout << " has_stem()-----------: " << p.has_stem() << std::endl; + std::cout << " has_extension()------: " << p.has_extension() << std::endl; return 0; } +//] diff --git a/example/tut0.cpp b/example/tut0.cpp index 4caa7c181..a78cbaa50 100644 --- a/example/tut0.cpp +++ b/example/tut0.cpp @@ -7,6 +7,7 @@ // Library home page: http://www.boost.org/libs/filesystem +//[example_tut0 #include #include @@ -16,9 +17,10 @@ int main(int argc, char* argv[]) { if (argc < 2) { - std::cout << "Usage: tut0 path\n"; + std::cout << "Usage: tut0 path" << std::endl; return 1; } - std::cout << argv[1] << '\n'; + std::cout << argv[1] << std::endl; return 0; } +//] diff --git a/example/tut1.cpp b/example/tut1.cpp index d04c4a314..6ddc8a955 100644 --- a/example/tut1.cpp +++ b/example/tut1.cpp @@ -7,6 +7,7 @@ // Library home page: http://www.boost.org/libs/filesystem +//[example_tut1 #include #include @@ -16,9 +17,10 @@ int main(int argc, char* argv[]) { if (argc < 2) { - std::cout << "Usage: tut1 path\n"; + std::cout << "Usage: tut1 path" << std::endl; return 1; } - std::cout << argv[1] << " " << file_size(argv[1]) << '\n'; + std::cout << argv[1] << " " << file_size(argv[1]) << std::endl; return 0; } +//] diff --git a/example/tut2.cpp b/example/tut2.cpp index 68b4a03a6..6764f8518 100644 --- a/example/tut2.cpp +++ b/example/tut2.cpp @@ -7,17 +7,17 @@ // Library home page: http://www.boost.org/libs/filesystem +//[example_tut2 #include #include -using namespace std; using namespace boost::filesystem; int main(int argc, char* argv[]) { if (argc < 2) { - cout << "Usage: tut2 path\n"; + std::cout << "Usage: tut2 path" << std::endl; return 1; } @@ -26,14 +26,15 @@ int main(int argc, char* argv[]) if (exists(p)) // does path p actually exist? { if (is_regular_file(p)) // is path p a regular file? - cout << p << " size is " << file_size(p) << '\n'; + std::cout << p << " size is " << file_size(p) << std::endl; else if (is_directory(p)) // is path p a directory? - cout << p << " is a directory\n"; + std::cout << p << " is a directory" << std::endl; else - cout << p << " exists, but is not a regular file or directory\n"; + std::cout << p << " exists, but is not a regular file or directory" << std::endl; } else - cout << p << " does not exist\n"; + std::cout << p << " does not exist" << std::endl; return 0; } +//] diff --git a/example/tut3.cpp b/example/tut3.cpp index c8a667d16..12fb055de 100644 --- a/example/tut3.cpp +++ b/example/tut3.cpp @@ -7,17 +7,17 @@ // Library home page: http://www.boost.org/libs/filesystem +//[example_tut3 #include #include -using std::cout; using namespace boost::filesystem; int main(int argc, char* argv[]) { if (argc < 2) { - cout << "Usage: tut3 path\n"; + std::cout << "Usage: tut3 path" << std::endl; return 1; } @@ -29,25 +29,26 @@ int main(int argc, char* argv[]) { if (is_regular_file(p)) { - cout << p << " size is " << file_size(p) << '\n'; + std::cout << p << " size is " << file_size(p) << std::endl; } else if (is_directory(p)) { - cout << p << " is a directory containing:\n"; + std::cout << p << " is a directory containing:" << std::endl; for (directory_entry const& x : directory_iterator(p)) - cout << " " << x.path() << '\n'; + std::cout << " " << x.path() << std::endl; } else - cout << p << " exists, but is not a regular file or directory\n"; + std::cout << p << " exists, but is not a regular file or directory" << std::endl; } else - cout << p << " does not exist\n"; + std::cout << p << " does not exist" << std::endl; } catch (filesystem_error& ex) { - cout << ex.what() << '\n'; + std::cout << ex.what() << std::endl; } return 0; } +//] diff --git a/example/tut4.cpp b/example/tut4.cpp index 3909c6236..6bd30d24b 100644 --- a/example/tut4.cpp +++ b/example/tut4.cpp @@ -7,19 +7,19 @@ // Library home page: http://www.boost.org/libs/filesystem +//[example_tut4 #include #include #include #include -using std::cout; using namespace boost::filesystem; int main(int argc, char* argv[]) { if (argc < 2) { - cout << "Usage: tut4 path\n"; + std::cout << "Usage: tut4 path" << std::endl; return 1; } @@ -31,13 +31,13 @@ int main(int argc, char* argv[]) { if (is_regular_file(p)) { - cout << p << " size is " << file_size(p) << '\n'; + std::cout << p << " size is " << file_size(p) << std::endl; } else if (is_directory(p)) { - cout << p << " is a directory containing:\n"; + std::cout << p << " is a directory containing:" << std::endl; - std::vector< path > v; + std::vector v; for (auto&& x : directory_iterator(p)) v.push_back(x.path()); @@ -45,18 +45,19 @@ int main(int argc, char* argv[]) std::sort(v.begin(), v.end()); for (auto&& x : v) - cout << " " << x.filename() << '\n'; + std::cout << " " << x.filename() << std::endl; } else - cout << p << " exists, but is not a regular file or directory\n"; + std::cout << p << " exists, but is not a regular file or directory" << std::endl; } else - cout << p << " does not exist\n"; + std::cout << p << " does not exist" << std::endl; } catch (filesystem_error& ex) { - cout << ex.what() << '\n'; + std::cout << ex.what() << std::endl; } return 0; } +//] diff --git a/example/tut5.cpp b/example/tut5.cpp index b9dd00d73..d9094b2bd 100644 --- a/example/tut5.cpp +++ b/example/tut5.cpp @@ -7,6 +7,7 @@ // Library home page: http://www.boost.org/libs/filesystem +//[example_tut5 #include #include #include @@ -67,3 +68,4 @@ int main() return 0; } +//] diff --git a/include/boost/filesystem/config.hpp b/include/boost/filesystem/config.hpp index 795a0fe2c..85d400f87 100644 --- a/include/boost/filesystem/config.hpp +++ b/include/boost/filesystem/config.hpp @@ -150,4 +150,24 @@ #define BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR #endif +#if !defined(BOOST_FILESYSTEM_DETAIL_DOC_ALT) +#if !defined(BOOST_FILESYSTEM_DOXYGEN) +#define BOOST_FILESYSTEM_DETAIL_DOC_ALT(alt, ...) __VA_ARGS__ +#else +#define BOOST_FILESYSTEM_DETAIL_DOC_ALT(alt, ...) alt +#endif +#endif + +#if !defined(BOOST_FILESYSTEM_DETAIL_DOC_HIDDEN) +#define BOOST_FILESYSTEM_DETAIL_DOC_HIDDEN(...) BOOST_FILESYSTEM_DETAIL_DOC_ALT(..., __VA_ARGS__) +#endif + +#if !defined(BOOST_FILESYSTEM_DETAIL_DOC) +#if !defined(BOOST_FILESYSTEM_DOXYGEN) +#define BOOST_FILESYSTEM_DETAIL_DOC(...) +#else +#define BOOST_FILESYSTEM_DETAIL_DOC(...) __VA_ARGS__ +#endif +#endif + #endif // BOOST_FILESYSTEM_CONFIG_HPP diff --git a/include/boost/filesystem/detail/path_traits.hpp b/include/boost/filesystem/detail/path_traits.hpp index 416c07378..fdcfe75e6 100644 --- a/include/boost/filesystem/detail/path_traits.hpp +++ b/include/boost/filesystem/detail/path_traits.hpp @@ -54,16 +54,16 @@ namespace detail { namespace path_traits { #if defined(BOOST_WINDOWS_API) -typedef wchar_t path_native_char_type; +using path_native_char_type = wchar_t; #define BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE false #define BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE true #else -typedef char path_native_char_type; +using path_native_char_type = char; #define BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE true #define BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE false #endif -typedef std::codecvt< wchar_t, char, std::mbstate_t > codecvt_type; +using codecvt_type = std::codecvt< wchar_t, char, std::mbstate_t >; struct unknown_type_tag {}; struct ntcts_type_tag {}; @@ -82,9 +82,9 @@ template< typename T > struct path_source_traits { //! The kind of the path source. Useful for dispatching. - typedef unknown_type_tag tag_type; + using tag_type = unknown_type_tag; //! Character type that the source contains - typedef void char_type; + using char_type = void; //! Indicates whether the source is natively supported by \c path::string_type as arguments for constructors/assignment/appending static BOOST_CONSTEXPR_OR_CONST bool is_native = false; }; @@ -92,128 +92,128 @@ struct path_source_traits template< > struct path_source_traits< char* > { - typedef char_ptr_tag tag_type; - typedef char char_type; + using tag_type = char_ptr_tag; + using char_type = char; static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE; }; template< > struct path_source_traits< const char* > { - typedef char_ptr_tag tag_type; - typedef char char_type; + using tag_type = char_ptr_tag; + using char_type = char; static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE; }; template< > struct path_source_traits< wchar_t* > { - typedef char_ptr_tag tag_type; - typedef wchar_t char_type; + using tag_type = char_ptr_tag; + using char_type = wchar_t; static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE; }; template< > struct path_source_traits< const wchar_t* > { - typedef char_ptr_tag tag_type; - typedef wchar_t char_type; + using tag_type = char_ptr_tag; + using char_type = wchar_t; static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE; }; template< > struct path_source_traits< char[] > { - typedef char_array_tag tag_type; - typedef char char_type; + using tag_type = char_array_tag; + using char_type = char; static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE; }; template< > struct path_source_traits< const char[] > { - typedef char_array_tag tag_type; - typedef char char_type; + using tag_type = char_array_tag; + using char_type = char; static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE; }; template< > struct path_source_traits< wchar_t[] > { - typedef char_array_tag tag_type; - typedef wchar_t char_type; + using tag_type = char_array_tag; + using char_type = wchar_t; static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE; }; template< > struct path_source_traits< const wchar_t[] > { - typedef char_array_tag tag_type; - typedef wchar_t char_type; + using tag_type = char_array_tag; + using char_type = wchar_t; static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE; }; template< std::size_t N > struct path_source_traits< char[N] > { - typedef char_array_tag tag_type; - typedef char char_type; + using tag_type = char_array_tag; + using char_type = char; static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE; }; template< std::size_t N > struct path_source_traits< const char[N] > { - typedef char_array_tag tag_type; - typedef char char_type; + using tag_type = char_array_tag; + using char_type = char; static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE; }; template< std::size_t N > struct path_source_traits< wchar_t[N] > { - typedef char_array_tag tag_type; - typedef wchar_t char_type; + using tag_type = char_array_tag; + using char_type = wchar_t; static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE; }; template< std::size_t N > struct path_source_traits< const wchar_t[N] > { - typedef char_array_tag tag_type; - typedef wchar_t char_type; + using tag_type = char_array_tag; + using char_type = wchar_t; static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE; }; template< > struct path_source_traits< std::string > { - typedef std_string_tag tag_type; - typedef char char_type; + using tag_type = std_string_tag; + using char_type = char; static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE; }; template< > struct path_source_traits< std::wstring > { - typedef std_string_tag tag_type; - typedef wchar_t char_type; + using tag_type = std_string_tag; + using char_type = wchar_t; static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE; }; template< > struct path_source_traits< boost::container::basic_string< char, std::char_traits< char >, void > > { - typedef boost_container_string_tag tag_type; - typedef char char_type; + using tag_type = boost_container_string_tag; + using char_type = char; static BOOST_CONSTEXPR_OR_CONST bool is_native = false; }; template< > struct path_source_traits< boost::container::basic_string< wchar_t, std::char_traits< wchar_t >, void > > { - typedef boost_container_string_tag tag_type; - typedef wchar_t char_type; + using tag_type = boost_container_string_tag; + using char_type = wchar_t; static BOOST_CONSTEXPR_OR_CONST bool is_native = false; }; @@ -222,16 +222,16 @@ struct path_source_traits< boost::container::basic_string< wchar_t, std::char_tr template< > struct path_source_traits< std::string_view > { - typedef std_string_view_tag tag_type; - typedef char char_type; + using tag_type = std_string_view_tag; + using char_type = char; static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_CHAR_NATIVE; }; template< > struct path_source_traits< std::wstring_view > { - typedef std_string_view_tag tag_type; - typedef wchar_t char_type; + using tag_type = std_string_view_tag; + using char_type = wchar_t; static BOOST_CONSTEXPR_OR_CONST bool is_native = BOOST_FILESYSTEM_DETAIL_IS_WCHAR_T_NATIVE; }; @@ -240,16 +240,16 @@ struct path_source_traits< std::wstring_view > template< > struct path_source_traits< boost::basic_string_view< char, std::char_traits< char > > > { - typedef boost_string_view_tag tag_type; - typedef char char_type; + using tag_type = boost_string_view_tag; + using char_type = char; static BOOST_CONSTEXPR_OR_CONST bool is_native = false; }; template< > struct path_source_traits< boost::basic_string_view< wchar_t, std::char_traits< wchar_t > > > { - typedef boost_string_view_tag tag_type; - typedef wchar_t char_type; + using tag_type = boost_string_view_tag; + using char_type = wchar_t; static BOOST_CONSTEXPR_OR_CONST bool is_native = false; }; @@ -260,8 +260,8 @@ BOOST_FILESYSTEM_DETAIL_DEPRECATED("Boost.Filesystem path construction/assignmen path_source_traits< std::vector< char > > { // Since C++11 this could be string_class_tag as std::vector gained data() member - typedef range_type_tag tag_type; - typedef char char_type; + using tag_type = range_type_tag; + using char_type = char; static BOOST_CONSTEXPR_OR_CONST bool is_native = false; }; @@ -271,8 +271,8 @@ BOOST_FILESYSTEM_DETAIL_DEPRECATED("Boost.Filesystem path construction/assignmen path_source_traits< std::vector< wchar_t > > { // Since C++11 this could be string_class_tag as std::vector gained data() member - typedef range_type_tag tag_type; - typedef wchar_t char_type; + using tag_type = range_type_tag; + using char_type = wchar_t; static BOOST_CONSTEXPR_OR_CONST bool is_native = false; }; @@ -281,8 +281,8 @@ struct BOOST_FILESYSTEM_DETAIL_DEPRECATED("Boost.Filesystem path construction/assignment/appending from containers is deprecated, use strings or iterators instead.") path_source_traits< std::list< char > > { - typedef range_type_tag tag_type; - typedef char char_type; + using tag_type = range_type_tag; + using char_type = char; static BOOST_CONSTEXPR_OR_CONST bool is_native = false; }; @@ -291,8 +291,8 @@ struct BOOST_FILESYSTEM_DETAIL_DEPRECATED("Boost.Filesystem path construction/assignment/appending from containers is deprecated, use strings or iterators instead.") path_source_traits< std::list< wchar_t > > { - typedef range_type_tag tag_type; - typedef wchar_t char_type; + using tag_type = range_type_tag; + using char_type = wchar_t; static BOOST_CONSTEXPR_OR_CONST bool is_native = false; }; #endif // defined(BOOST_FILESYSTEM_DEPRECATED) && BOOST_FILESYSTEM_VERSION < 4 @@ -300,8 +300,8 @@ path_source_traits< std::list< wchar_t > > template< > struct path_source_traits< directory_entry > { - typedef directory_entry_tag tag_type; - typedef path_native_char_type char_type; + using tag_type = directory_entry_tag; + using char_type = path_native_char_type; static BOOST_CONSTEXPR_OR_CONST bool is_native = false; }; @@ -477,7 +477,7 @@ BOOST_FORCEINLINE typename Callback::result_type dispatch(Source const& source, } -typedef char yes_type; +using yes_type = char; struct no_type { char buf[2]; }; #if !defined(BOOST_FILESYSTEM_DETAIL_CXX23_STRING_VIEW_HAS_IMPLICIT_RANGE_CTOR) @@ -580,34 +580,34 @@ struct is_convertible_to_path_source : template< typename T, typename > struct make_dependent { - typedef T type; + using type = T; }; template< typename Source, typename Callback > BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(const char* source, Callback cb, const codecvt_type* cvt) { - typedef typename path_traits::make_dependent< const char*, Source >::type source_t; + using source_t = typename path_traits::make_dependent< const char*, Source >::type; return path_traits::dispatch(static_cast< source_t >(source), cb, cvt); } template< typename Source, typename Callback > BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(const wchar_t* source, Callback cb, const codecvt_type* cvt) { - typedef typename path_traits::make_dependent< const wchar_t*, Source >::type source_t; + using source_t = typename path_traits::make_dependent< const wchar_t*, Source >::type; return path_traits::dispatch(static_cast< source_t >(source), cb, cvt); } template< typename Source, typename Callback > BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(std::string const& source, Callback cb, const codecvt_type* cvt) { - typedef typename path_traits::make_dependent< std::string, Source >::type source_t; + using source_t = typename path_traits::make_dependent< std::string, Source >::type; return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); } template< typename Source, typename Callback > BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(std::wstring const& source, Callback cb, const codecvt_type* cvt) { - typedef typename path_traits::make_dependent< std::wstring, Source >::type source_t; + using source_t = typename path_traits::make_dependent< std::wstring, Source >::type; return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); } @@ -619,7 +619,7 @@ BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl const codecvt_type* cvt ) { - typedef typename path_traits::make_dependent< boost::container::basic_string< char, std::char_traits< char >, void >, Source >::type source_t; + using source_t = typename path_traits::make_dependent< boost::container::basic_string< char, std::char_traits< char >, void >, Source >::type; return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); } @@ -631,7 +631,7 @@ BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl const codecvt_type* cvt ) { - typedef typename path_traits::make_dependent< boost::container::basic_string< wchar_t, std::char_traits< wchar_t >, void >, Source >::type source_t; + using source_t = typename path_traits::make_dependent< boost::container::basic_string< wchar_t, std::char_traits< wchar_t >, void >, Source >::type; return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); } @@ -643,7 +643,7 @@ BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl const codecvt_type* cvt ) { - typedef typename path_traits::make_dependent< boost::basic_string_view< char, std::char_traits< char > >, Source >::type source_t; + using source_t = typename path_traits::make_dependent< boost::basic_string_view< char, std::char_traits< char > >, Source >::type; return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); } @@ -655,7 +655,7 @@ BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl const codecvt_type* cvt ) { - typedef typename path_traits::make_dependent< boost::basic_string_view< wchar_t, std::char_traits< wchar_t > >, Source >::type source_t; + using source_t = typename path_traits::make_dependent< boost::basic_string_view< wchar_t, std::char_traits< wchar_t > >, Source >::type; return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); } @@ -666,14 +666,14 @@ BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl template< typename Source, typename Callback > BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(std::string_view const& source, Callback cb, const codecvt_type* cvt) { - typedef typename path_traits::make_dependent< std::string_view, Source >::type source_t; + using source_t = typename path_traits::make_dependent< std::string_view, Source >::type; return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); } template< typename Source, typename Callback > BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(std::wstring_view const& source, Callback cb, const codecvt_type* cvt) { - typedef typename path_traits::make_dependent< std::wstring_view, Source >::type source_t; + using source_t = typename path_traits::make_dependent< std::wstring_view, Source >::type; return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); } @@ -682,7 +682,7 @@ BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_impl(std:: template< typename Source, typename Callback > BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible(Source const& source, Callback cb, const codecvt_type* cvt = nullptr) { - typedef typename std::remove_cv< Source >::type source_t; + using source_t = typename std::remove_cv< Source >::type; return path_traits::dispatch_convertible_impl< source_t >(source, cb, cvt); } @@ -691,14 +691,14 @@ BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible(Source con template< typename Source, typename Callback > BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_sv_impl(std::string_view const& source, Callback cb, const codecvt_type* cvt) { - typedef typename path_traits::make_dependent< std::string_view, Source >::type source_t; + using source_t = typename path_traits::make_dependent< std::string_view, Source >::type; return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); } template< typename Source, typename Callback > BOOST_FORCEINLINE typename Callback::result_type dispatch_convertible_sv_impl(std::wstring_view const& source, Callback cb, const codecvt_type* cvt) { - typedef typename path_traits::make_dependent< std::wstring_view, Source >::type source_t; + using source_t = typename path_traits::make_dependent< std::wstring_view, Source >::type; return path_traits::dispatch(static_cast< source_t const& >(source), cb, cvt); } @@ -708,7 +708,7 @@ BOOST_FORCEINLINE typename std::enable_if< typename Callback::result_type >::type dispatch_convertible(Source const& source, Callback cb, const codecvt_type* cvt = nullptr) { - typedef typename std::remove_cv< Source >::type source_t; + using source_t = typename std::remove_cv< Source >::type; return path_traits::dispatch_convertible_impl< source_t >(source, cb, cvt); } @@ -718,7 +718,7 @@ BOOST_FORCEINLINE typename std::enable_if< typename Callback::result_type >::type dispatch_convertible(Source const& source, Callback cb, const codecvt_type* cvt = nullptr) { - typedef typename std::remove_cv< Source >::type source_t; + using source_t = typename std::remove_cv< Source >::type; return path_traits::dispatch_convertible_sv_impl< source_t >(source, cb, cvt); } diff --git a/include/boost/filesystem/directory.hpp b/include/boost/filesystem/directory.hpp index 821b1a97b..7a94886e9 100644 --- a/include/boost/filesystem/directory.hpp +++ b/include/boost/filesystem/directory.hpp @@ -40,16 +40,19 @@ namespace boost { namespace filesystem { +//! \hideinitializer enum class directory_options : unsigned int { none = 0u, - skip_permission_denied = 1u, // if a directory cannot be opened because of insufficient permissions, pretend that the directory is empty - follow_directory_symlink = 1u << 1u, // recursive_directory_iterator: follow directory symlinks - skip_dangling_symlinks = 1u << 2u, // non-standard extension for recursive_directory_iterator: don't follow dangling directory symlinks, - pop_on_error = 1u << 3u, // non-standard extension for recursive_directory_iterator: instead of producing an end iterator on errors, - // repeatedly invoke pop() until it succeeds or the iterator becomes equal to end iterator + skip_permission_denied = 1u, //!< If a directory cannot be opened because of insufficient permissions, pretend that the directory is empty + follow_directory_symlink = 1u << 1u, //!< `recursive_directory_iterator`: follow directory symlinks + skip_dangling_symlinks = 1u << 2u, //!< Non-standard extension for `recursive_directory_iterator`: don't follow dangling directory symlinks, + pop_on_error = 1u << 3u, /*!< non-standard extension for `recursive_directory_iterator`: instead of producing an end iterator on errors, + * repeatedly invoke `pop()` until it succeeds or the iterator becomes equal to end iterator */ +#if !defined(BOOST_FILESYSTEM_DOXYGEN) _detail_no_follow = 1u << 4u, // internal use only _detail_no_push = 1u << 5u // internal use only +#endif }; BOOST_BITMASK(directory_options) diff --git a/include/boost/filesystem/operations.hpp b/include/boost/filesystem/operations.hpp index 5cd40a30f..557bf0ff9 100644 --- a/include/boost/filesystem/operations.hpp +++ b/include/boost/filesystem/operations.hpp @@ -41,26 +41,29 @@ struct space_info boost::uintmax_t available; // <= free }; +//! \hideinitializer enum class copy_options : unsigned int { - none = 0u, // Default. For copy_file: error if the target file exists. For copy: do not recurse, follow symlinks, copy file contents. + none = 0u, //!< Default. For copy_file: error if the target file exists. For copy: do not recurse, follow symlinks, copy file contents. // copy_file options: - skip_existing = 1u, // Don't overwrite the existing target file, don't report an error - overwrite_existing = 1u << 1u, // Overwrite existing file - update_existing = 1u << 2u, // Overwrite existing file if its last write time is older than the replacement file - synchronize_data = 1u << 3u, // Flush all buffered data written to the target file to permanent storage - synchronize = 1u << 4u, // Flush all buffered data and attributes written to the target file to permanent storage - ignore_attribute_errors = 1u << 5u, // Ignore errors of copying file attributes + skip_existing = 1u, //!< Don't overwrite the existing target file, don't report an error + overwrite_existing = 1u << 1u, //!< Overwrite existing file + update_existing = 1u << 2u, //!< Overwrite existing file if its last write time is older than the replacement file + synchronize_data = 1u << 3u, //!< Flush all buffered data written to the target file to permanent storage + synchronize = 1u << 4u, //!< Flush all buffered data and attributes written to the target file to permanent storage + ignore_attribute_errors = 1u << 5u, //!< Ignore errors of copying file attributes // copy options: - recursive = 1u << 8u, // Recurse into sub-directories - copy_symlinks = 1u << 9u, // Copy symlinks as symlinks instead of copying the referenced file - skip_symlinks = 1u << 10u, // Don't copy symlinks - directories_only = 1u << 11u, // Only copy directory structure, do not copy non-directory files - create_symlinks = 1u << 12u, // Create symlinks instead of copying files - create_hard_links = 1u << 13u, // Create hard links instead of copying files + recursive = 1u << 8u, //!< Recurse into sub-directories + copy_symlinks = 1u << 9u, //!< Copy symlinks as symlinks instead of copying the referenced file + skip_symlinks = 1u << 10u, //!< Don't copy symlinks + directories_only = 1u << 11u, //!< Only copy directory structure, do not copy non-directory files + create_symlinks = 1u << 12u, //!< Create symlinks instead of copying files + create_hard_links = 1u << 13u, //!< Create hard links instead of copying files +#if !defined(BOOST_FILESYSTEM_DOXYGEN) _detail_recursing = 1u << 14u // Internal use only, do not use +#endif }; BOOST_BITMASK(copy_options) diff --git a/include/boost/filesystem/path.hpp b/include/boost/filesystem/path.hpp index f6e38f4b2..af0776d75 100644 --- a/include/boost/filesystem/path.hpp +++ b/include/boost/filesystem/path.hpp @@ -43,13 +43,14 @@ namespace filesystem { class path; -namespace path_detail { // intentionally don't use filesystem::detail to not bring internal Boost.Filesystem functions into ADL via path_constants +namespace detail { +namespace path_impl { // intentionally don't use filesystem::detail to not bring internal Boost.Filesystem functions into ADL via path_constants template< typename Char, Char Separator, Char PreferredSeparator, Char Dot > struct path_constants { - typedef path_constants< Char, Separator, PreferredSeparator, Dot > path_constants_base; - typedef Char value_type; + using path_constants_base = path_constants< Char, Separator, PreferredSeparator, Dot >; + using value_type = Char; static BOOST_CONSTEXPR_OR_CONST value_type separator = Separator; static BOOST_CONSTEXPR_OR_CONST value_type preferred_separator = PreferredSeparator; static BOOST_CONSTEXPR_OR_CONST value_type dot = Dot; @@ -70,9 +71,7 @@ path_constants< Char, Separator, PreferredSeparator, Dot >::dot; class path_iterator; class path_reverse_iterator; -} // namespace path_detail - -namespace detail { +} // namespace path_impl struct path_algorithms { @@ -83,8 +82,8 @@ struct path_algorithms std::size_t size; }; - typedef path_traits::path_native_char_type value_type; - typedef std::basic_string< value_type > string_type; + using value_type = path_traits::path_native_char_type; + using string_type = std::basic_string< value_type >; static bool has_filename_v3(path const& p); static bool has_filename_v4(path const& p); @@ -135,31 +134,56 @@ struct path_algorithms BOOST_FILESYSTEM_DECL static int lex_compare_v3 ( - path_detail::path_iterator first1, path_detail::path_iterator const& last1, - path_detail::path_iterator first2, path_detail::path_iterator const& last2 + path_impl::path_iterator first1, path_impl::path_iterator const& last1, + path_impl::path_iterator first2, path_impl::path_iterator const& last2 ); BOOST_FILESYSTEM_DECL static int lex_compare_v4 ( - path_detail::path_iterator first1, path_detail::path_iterator const& last1, - path_detail::path_iterator first2, path_detail::path_iterator const& last2 + path_impl::path_iterator first1, path_impl::path_iterator const& last1, + path_impl::path_iterator first2, path_impl::path_iterator const& last2 ); - BOOST_FILESYSTEM_DECL static void increment_v3(path_detail::path_iterator& it); - BOOST_FILESYSTEM_DECL static void increment_v4(path_detail::path_iterator& it); - BOOST_FILESYSTEM_DECL static void decrement_v3(path_detail::path_iterator& it); - BOOST_FILESYSTEM_DECL static void decrement_v4(path_detail::path_iterator& it); + BOOST_FILESYSTEM_DECL static void increment_v3(path_impl::path_iterator& it); + BOOST_FILESYSTEM_DECL static void increment_v4(path_impl::path_iterator& it); + BOOST_FILESYSTEM_DECL static void decrement_v3(path_impl::path_iterator& it); + BOOST_FILESYSTEM_DECL static void decrement_v4(path_impl::path_iterator& it); }; } // namespace detail -//------------------------------------------------------------------------------------// -// // -// class path // -// // -//------------------------------------------------------------------------------------// - +/*! + * \brief Filesystem path class + * + * An object of class `path` represents a path, and contains a pathname. Such an object is concerned + * only with the lexical and syntactic aspects of a path. The path does not necessarily exist in external + * storage, and the pathname is not necessarily valid for the current operating system or for a particular + * file system. + * + * Class `path` supports a variety of methods for observing and modifying the path. Among the modifiers, + * there are two groups of methods for performing concatenation and appending. The important distinction + * between these two groups is that concatenation is performed on the path as if the path was a simple + * string (i.e. the concatenated characters are placed immediately at the end of the path), while appending + * maintains path structure and may insert a directory separator before the appended characters. The rules + * for inserting the separator depend on the library version and are documented in the \ref path::append + * method description. + * + * Class `path` supports iterators over its elements: + * + *
+ * [root-name?] [root-directory?] [filename*]
+ * 
+ * + * Note that dereferencing a path iterator produces a path. + * + * \par `path` imbued locale + * + * `path` operations sometimes require encoding conversions between pathname and some other string object + * where one of the value types is `path::value_type` and the other is another path character type. Such + * conversions shall be performed by the `path::codecvt()` facet by default, unless another facet is + * specified in the operation. + */ class path : - public filesystem::path_detail::path_constants< + public detail::path_impl::path_constants< #ifdef BOOST_WINDOWS_API detail::path_traits::path_native_char_type, L'/', L'\\', L'.' #else @@ -167,17 +191,40 @@ class path : #endif > { - friend class path_detail::path_iterator; - friend class path_detail::path_reverse_iterator; + friend class detail::path_impl::path_iterator; + friend class detail::path_impl::path_reverse_iterator; friend struct detail::path_algorithms; public: - // value_type is the character type used by the operating system API to - // represent paths. + //! Character type used by the operating system API to represent paths + using value_type = detail::path_algorithms::value_type; +#if !defined(BOOST_FILESYSTEM_DOXYGEN) + using string_type = detail::path_algorithms::string_type; + using codecvt_type = detail::path_traits::codecvt_type; +#else + //! String type used by the operating system API to represent paths + using string_type = std::basic_string< value_type >; + //! Character code conversion facet type used to convert path strings between character types + using codecvt_type = std::codecvt< wchar_t, char, std::mbstate_t >; - typedef detail::path_algorithms::value_type value_type; - typedef detail::path_algorithms::string_type string_type; - typedef detail::path_traits::codecvt_type codecvt_type; + /*! + * Character used to separate path elements in generic paths. + */ + static constexpr value_type separator = detail::separator; + /*! + * Character used to separate path elements in native paths. + * + * This character may be the same as `separator` or different and depends on the target platform + * conventions. It is "/" on POSIX systems and "\" on Windows. + */ + static constexpr value_type preferred_separator = detail::preferred_separator; + /*! + * Character used to separate file name and extension. + * + * It is "." on POSIX systems and Windows. + */ + static constexpr value_type dot = detail::dot; +#endif // ----- character encoding conversions ----- @@ -235,6 +282,7 @@ class path : // as a result of such failues occur after main() has started, so can be caught. private: + //! \cond //! Assignment operation class assign_op { @@ -242,7 +290,7 @@ class path : path& m_self; public: - typedef void result_type; + using result_type = void; explicit assign_op(path& self) noexcept : m_self(self) {} @@ -266,7 +314,7 @@ class path : path& m_self; public: - typedef void result_type; + using result_type = void; explicit concat_op(path& self) noexcept : m_self(self) {} @@ -289,7 +337,7 @@ class path : path& m_self; public: - typedef void result_type; + using result_type = void; explicit append_op(path& self) noexcept : m_self(self) {} @@ -314,7 +362,7 @@ class path : path const& m_self; public: - typedef int result_type; + using result_type = int; explicit compare_op(path const& self) noexcept : m_self(self) {} @@ -324,19 +372,81 @@ class path : result_type operator() (const OtherChar* source, const OtherChar* source_end, const codecvt_type* cvt = nullptr) const; }; -public: - typedef path_detail::path_iterator iterator; - typedef iterator const_iterator; - typedef path_detail::path_reverse_iterator reverse_iterator; - typedef reverse_iterator const_reverse_iterator; + //! \endcond public: - // ----- constructors ----- + //! Iterator over path elements + using iterator = detail::path_impl::path_iterator; + //! Iterator over path elements + using const_iterator = detail::path_impl::path_iterator; + //! Reverse iterator over path elements + using reverse_iterator = detail::path_impl::path_reverse_iterator; + //! Reverse iterator over path elements + using const_reverse_iterator = detail::path_impl::path_reverse_iterator; +public: + //! \name constructors + //! @{ + + /*! + * \brief Default constructor. + * + * **Effects:** Constructs an empty path. + * + * **Throws:** Nothing. + * + * \post `this->empty() == true`. + */ path() noexcept {} + /*! + * \brief Copy constructor. + * + * **Effects:** Constructs a copy of \a p. + * + * **Throws:** `std::bad_alloc` on memory allocation failure. + * + * \param p Path object to copy. + * + * \post `*this == p`. + */ path(path const& p) : m_pathname(p.m_pathname) {} - path(path const& p, codecvt_type const&) : m_pathname(p.m_pathname) {} + /*! + * \brief Copy constructor. + * + * **Effects:** As if `path(p)`. + * + * \note The \a cvt character code conversion facet is unused and provided for historical reasons, + * for signature compatibility with constructors performing character code conversion. + */ + path(path const& p, codecvt_type const& cvt) : m_pathname(p.m_pathname) {} + + /*! + * \brief Move constructor. + * + * **Effects:** Move-constructs from \a p. + * + * **Throws:** Nothing. + * + * \param p Path object to move from. + * + * \post `*this` is equal to \a p before the operation. + */ + path(path&& p) noexcept : m_pathname(static_cast< string_type&& >(p.m_pathname)) + { + } + /*! + * \brief Move constructor. + * + * **Effects:** As if `path(std::move(p))`. + * + * \note The \a cvt character code conversion facet is unused and provided for historical reasons, + * for signature compatibility with constructors performing character code conversion. + */ + path(path&& p, codecvt_type const& cvt) noexcept : m_pathname(static_cast< string_type&& >(p.m_pathname)) + { + } + //! \cond path(const value_type* s) : m_pathname(s) {} path(const value_type* s, codecvt_type const&) : m_pathname(s) {} path(string_type const& s) : m_pathname(s) {} @@ -345,157 +455,321 @@ class path : path(std::basic_string_view< value_type > const& s) : m_pathname(s) {} path(std::basic_string_view< value_type > const& s, codecvt_type const&) : m_pathname(s) {} #endif + //! \endcond + /*! + * \brief Initializing constructor. + * + * **Effects:** As if `path(source, path::codecvt())`. + */ template< - typename Source, - typename = typename std::enable_if< + typename Source + //! \cond + , typename = typename std::enable_if< detail::conjunction< detail::path_traits::is_path_source< typename std::remove_cv< Source >::type >, detail::negation< detail::path_traits::is_native_path_source< typename std::remove_cv< Source >::type > > >::value >::type + //! \endcond > path(Source const& source) { assign(source); } + /*! + * \brief Initializing constructor. + * + * **Effects:** Constructs a path from \a source. Uses \a cvt facet to perform character code conversion, + * if needed. + * + * **Throws:** `std::bad_alloc` on memory allocation failure, `boost::system::system_error` in case + * of character code conversion errors. + * + * \param source Path source to construct the path from. + * \param cvt Character code conversion facet. + * + * \pre \a source is a valid path source. + */ template< - typename Source, - typename = typename std::enable_if< + typename Source + //! \cond + , typename = typename std::enable_if< detail::conjunction< detail::path_traits::is_path_source< typename std::remove_cv< Source >::type >, detail::negation< detail::path_traits::is_native_path_source< typename std::remove_cv< Source >::type > > >::value >::type + //! \endcond > explicit path(Source const& source, codecvt_type const& cvt) { assign(source, cvt); } - path(path&& p) noexcept : m_pathname(static_cast< string_type&& >(p.m_pathname)) - { - } - path(path&& p, codecvt_type const&) noexcept : m_pathname(static_cast< string_type&& >(p.m_pathname)) - { - } - path& operator=(path&& p) noexcept - { - m_pathname = static_cast< string_type&& >(p.m_pathname); - return *this; - } - path& assign(path&& p) noexcept - { - m_pathname = static_cast< string_type&& >(p.m_pathname); - return *this; - } - path& assign(path&& p, codecvt_type const&) noexcept - { - m_pathname = static_cast< string_type&& >(p.m_pathname); - return *this; - } - + /*! + * \brief Initializing constructor. + * + * **Effects:** Constructs a path by moving from \a s. + * + * **Throws:** Nothing. + * + * \param s Path source to construct the path from. + * + * \post `*this` is equal to \a s before the operation. + */ path(string_type&& s) noexcept : m_pathname(static_cast< string_type&& >(s)) { } - path(string_type&& s, codecvt_type const&) noexcept : m_pathname(static_cast< string_type&& >(s)) - { - } - path& operator=(string_type&& p) noexcept + /*! + * \brief Initializing constructor. + * + * **Effects:** As if `path(std::move(s))`. + * + * \note The \a cvt character code conversion facet is unused and provided for historical reasons, + * for signature compatibility with constructors performing character code conversion. + */ + path(string_type&& s, codecvt_type const& cvt) noexcept : m_pathname(static_cast< string_type&& >(s)) { - m_pathname = static_cast< string_type&& >(p); - return *this; - } - path& assign(string_type&& p) noexcept - { - m_pathname = static_cast< string_type&& >(p); - return *this; - } - path& assign(string_type&& p, codecvt_type const&) noexcept - { - m_pathname = static_cast< string_type&& >(p); - return *this; } + //! \cond path(const value_type* begin, const value_type* end) : m_pathname(begin, end) {} path(const value_type* begin, const value_type* end, codecvt_type const&) : m_pathname(begin, end) {} + //! \endcond + /*! + * \brief Initializing constructor. + * + * **Effects:** As if `path(begin, end, path::codecvt())`. + */ template< - typename InputIterator, - typename = typename std::enable_if< + typename InputIterator + //! \cond + , typename = typename std::enable_if< detail::conjunction< detail::path_traits::is_path_source_iterator< InputIterator >, detail::negation< detail::path_traits::is_native_char_ptr< InputIterator > > >::value >::type + //! \endcond > path(InputIterator begin, InputIterator end) { if (begin != end) { - typedef std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source_t; + using source_t = std::basic_string< typename std::iterator_traits< InputIterator >::value_type >; source_t source(begin, end); assign(static_cast< source_t&& >(source)); } } + /*! + * \brief Initializing constructor. + * + * **Effects:** Constructs a path from a range of characters denoted by \a begin and \a end. Uses \a cvt + * facet to perform character code conversion, if needed. + * + * **Throws:** `std::bad_alloc` on memory allocation failure, `boost::system::system_error` in case + * of character code conversion errors. + * + * \param begin Iterator pointing to the beginning of the range of characters to construct the path from. + * \param end Iterator pointing to the end of the range of characters to construct the path from. + * \param cvt Character code conversion facet. + * + * \pre `[begin, end)` is a valid range of path characters. + */ template< - typename InputIterator, - typename = typename std::enable_if< + typename InputIterator + //! \cond + , typename = typename std::enable_if< detail::conjunction< detail::path_traits::is_path_source_iterator< InputIterator >, detail::negation< detail::path_traits::is_native_char_ptr< InputIterator > > >::value >::type + //! \endcond > path(InputIterator begin, InputIterator end, codecvt_type const& cvt) { if (begin != end) { - typedef std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source_t; + using source_t = std::basic_string< typename std::iterator_traits< InputIterator >::value_type >; source_t source(begin, end); assign(static_cast< source_t&& >(source), cvt); } } + //! Constructor from null pointers is disabled path(std::nullptr_t) = delete; - path& operator= (std::nullptr_t) = delete; -public: - // ----- assignments ----- + //! @} + + //! \name assignment + //! @{ - // We need to explicitly define copy assignment as otherwise it will be implicitly defined as deleted because there is move assignment + /*! + * \brief Copy assignment. + * + * \returns `assign(p)`. + */ path& operator=(path const& p); + /*! + * \brief Copy assignment. + * + * **Effects:** Copies the path \a p into `*this`. + * + * **Throws:** `std::bad_alloc` on memory allocation failure. + * + * \param p Path to assign. + * \returns `*this`. + * + * \post `*this == p`. + */ + path& assign(path const& p) + { + m_pathname = p.m_pathname; + return *this; + } + /*! + * \brief Copy assignment. + * + * \returns `assign(p)`. + * + * \note The \a cvt character code conversion facet is unused and provided for historical reasons, + * for signature compatibility with overloads performing character code conversion. + */ + path& assign(path const& p, codecvt_type const& cvt) + { + m_pathname = p.m_pathname; + return *this; + } + + /*! + * \brief Move assignment. + * + * \returns `assign(std::move(p))`. + */ + path& operator=(path&& p) noexcept + { + m_pathname = static_cast< string_type&& >(p.m_pathname); + return *this; + } + /*! + * \brief Move assignment. + * + * **Effects:** Move-assigns the path \a p to `*this`. + * + * **Throws:** Nothing. + * + * \param p Path to assign. + * \returns `*this`. + * + * \post `*this == p`. + */ + path& assign(path&& p) noexcept + { + m_pathname = static_cast< string_type&& >(p.m_pathname); + return *this; + } + /*! + * \brief Move assignment. + * + * \returns `assign(std::move(p))`. + * + * \note The \a cvt character code conversion facet is unused and provided for historical reasons, + * for signature compatibility with overloads performing character code conversion. + */ + path& assign(path&& p, codecvt_type const& cvt) noexcept + { + m_pathname = static_cast< string_type&& >(p.m_pathname); + return *this; + } + + /*! + * \brief Move-assigns characters in the string to the path. + * + * \returns `assign(std::move(s))`. + */ + path& operator=(string_type&& s) noexcept + { + m_pathname = static_cast< string_type&& >(s); + return *this; + } + /*! + * \brief Move-assigns characters in the string to the path. + * + * **Effects:** Move-assigns the string \a s to `*this`. + * + * **Throws:** Nothing. + * + * \param s String to assign. + * \returns `*this`. + * + * \post `*this == s`. + */ + path& assign(string_type&& s) noexcept + { + m_pathname = static_cast< string_type&& >(s); + return *this; + } + /*! + * \brief Move-assigns characters in the string to the path. + * + * \returns `assign(std::move(s))`. + * + * \note The \a cvt character code conversion facet is unused and provided for historical reasons, + * for signature compatibility with overloads performing character code conversion. + */ + path& assign(string_type&& s, codecvt_type const& cvt) noexcept + { + m_pathname = static_cast< string_type&& >(s); + return *this; + } + /*! + * \brief Assigns characters in \a source to the path. + * + * \returns `assign(source)`. + */ template< typename Source > +#if !defined(BOOST_FILESYSTEM_DOXYGEN) typename std::enable_if< detail::disjunction< detail::path_traits::is_path_source< typename std::remove_cv< Source >::type >, detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type > >::value, path& - >::type operator=(Source const& source) + >::type +#else + path& +#endif + operator=(Source const& source) { return assign(source); } - - path& assign(path const& p) - { - m_pathname = p.m_pathname; - return *this; - } - + /*! + * \brief Assigns characters in \a source to the path. + * + * \returns `assign(source, path::codecvt())`. + */ template< typename Source > +#if !defined(BOOST_FILESYSTEM_DOXYGEN) typename std::enable_if< detail::path_traits::is_path_source< typename std::remove_cv< Source >::type >::value, path& - >::type assign(Source const& source) + >::type +#else + path& +#endif + assign(Source const& source) { detail::path_traits::dispatch(source, assign_op(*this)); return *this; } + //! \cond template< typename Source > typename std::enable_if< detail::conjunction< @@ -508,23 +782,39 @@ class path : detail::path_traits::dispatch_convertible(source, assign_op(*this)); return *this; } - - path& assign(path const& p, codecvt_type const&) - { - m_pathname = p.m_pathname; - return *this; - } - + //! \endcond + + /*! + * \brief Assigns characters in \a source to the path. + * + * **Effects:** Assigns \a source to `*this`. Uses \a cvt facet to perform character code conversion, + * if needed. + * + * **Throws:** `std::bad_alloc` on memory allocation failure, `boost::system::system_error` in case + * of character code conversion errors. + * + * \param source Path source to assign to the path object. + * \param cvt Character code conversion facet. + * \returns `*this`. + * + * \pre \a source is a valid path source. + */ template< typename Source > +#if !defined(BOOST_FILESYSTEM_DOXYGEN) typename std::enable_if< detail::path_traits::is_path_source< typename std::remove_cv< Source >::type >::value, path& - >::type assign(Source const& source, codecvt_type const& cvt) + >::type +#else + path& +#endif + assign(Source const& source, codecvt_type const& cvt) { detail::path_traits::dispatch(source, assign_op(*this), &cvt); return *this; } + //! \cond template< typename Source > typename std::enable_if< detail::conjunction< @@ -544,98 +834,197 @@ class path : return *this; } + path& assign(const value_type* begin, const value_type* end, codecvt_type const&) + { + m_pathname.assign(begin, end); + return *this; + } + //! \endcond + + /*! + * \brief Assigns characters in the iterator range to the path. + * + * \returns `assign(begin, end, path::codecvt())`. + */ template< typename InputIterator > +#if !defined(BOOST_FILESYSTEM_DOXYGEN) typename std::enable_if< detail::conjunction< detail::path_traits::is_path_source_iterator< InputIterator >, detail::negation< detail::path_traits::is_native_char_ptr< InputIterator > > >::value, path& - >::type assign(InputIterator begin, InputIterator end) + >::type +#else + path& +#endif + assign(InputIterator begin, InputIterator end) { m_pathname.clear(); if (begin != end) { - typedef std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source_t; + using source_t = std::basic_string< typename std::iterator_traits< InputIterator >::value_type >; source_t source(begin, end); assign(static_cast< source_t&& >(source)); } return *this; } - path& assign(const value_type* begin, const value_type* end, codecvt_type const&) - { - m_pathname.assign(begin, end); - return *this; - } - + /*! + * \brief Assigns characters in the iterator range to the path. + * + * **Effects:** Assigns a range of characters denoted by \a begin and \a end to `*this`. Uses \a cvt + * facet to perform character code conversion, if needed. + * + * **Throws:** `std::bad_alloc` on memory allocation failure, `boost::system::system_error` in case + * of character code conversion errors. + * + * \param begin Iterator pointing to the beginning of the range of characters to assign to the path. + * \param end Iterator pointing to the end of the range of characters to assign to the path. + * \param cvt Character code conversion facet. + * \returns `*this`. + * + * \pre `[begin, end)` is a valid range of path characters. + */ template< typename InputIterator > +#if !defined(BOOST_FILESYSTEM_DOXYGEN) typename std::enable_if< detail::conjunction< detail::path_traits::is_path_source_iterator< InputIterator >, detail::negation< detail::path_traits::is_native_char_ptr< InputIterator > > >::value, path& - >::type assign(InputIterator begin, InputIterator end, codecvt_type const& cvt) + >::type +#else + path& +#endif + assign(InputIterator begin, InputIterator end, codecvt_type const& cvt) { m_pathname.clear(); if (begin != end) { - typedef std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source_t; + using source_t = std::basic_string< typename std::iterator_traits< InputIterator >::value_type >; source_t source(begin, end); assign(static_cast< source_t&& >(source), cvt); } return *this; } - // ----- concatenation ----- + //! Assignment from null pointers is disabled + path& operator= (std::nullptr_t) = delete; - path& operator+=(path const& p); + //! @} - template< typename Source > - typename std::enable_if< - detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >::value, - path& - >::type operator+=(Source const& source) - { - return concat(source); - } + //! \name concatenation + //! @{ + //! \cond path& operator+=(value_type c) { m_pathname.push_back(c); return *this; } - - template< typename CharT > + //! \endcond + + /*! + * \brief Concatenates character \a c to the end of the path. + * + * \returns `concat(&c, &c + 1)`. + * + * \pre \c Char is a path character type. + */ + template< typename Char > +#if !defined(BOOST_FILESYSTEM_DOXYGEN) typename std::enable_if< - detail::path_traits::is_path_char_type< CharT >::value, + detail::path_traits::is_path_char_type< Char >::value, path& - >::type operator+=(CharT c) + >::type +#else + path& +#endif + operator+=(Char c) { - CharT tmp[2]; + Char tmp[2]; tmp[0] = c; - tmp[1] = static_cast< CharT >(0); + tmp[1] = static_cast< Char >(0); concat_op(*this)(tmp, tmp + 1); return *this; } + /*! + * \brief Concatenates characters from \a p to the end of the path. + * + * \returns `concat(p)`. + */ + path& operator+=(path const& p); + /*! + * \brief Concatenates characters from \a p to the end of the path. + * + * **Effects:** Copies the path \a p to the end of `*this`. + * + * **Throws:** `std::bad_alloc` on memory allocation failure. + * + * \param p Path to concatenate. + * \returns `*this`. + */ path& concat(path const& p) { m_pathname.append(p.m_pathname); return *this; } + /*! + * \brief Concatenates characters from \a p to the end of the path. + * + * \returns `concat(p)`. + * + * \note The \a cvt character code conversion facet is unused and provided for historical reasons, + * for signature compatibility with overloads performing character code conversion. + */ + path& concat(path const& p, codecvt_type const& cvt) + { + m_pathname.append(p.m_pathname); + return *this; + } + /*! + * \brief Concatenates characters from \a source to the end of the path. + * + * \returns `concat(source)`. + */ + template< typename Source > +#if !defined(BOOST_FILESYSTEM_DOXYGEN) + typename std::enable_if< + detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >::value, + path& + >::type +#else + path& +#endif + operator+=(Source const& source) + { + return concat(source); + } + /*! + * \brief Concatinates characters from \a source to the end of the path. + * + * \returns `concat(source, path::codecvt())`. + */ template< typename Source > +#if !defined(BOOST_FILESYSTEM_DOXYGEN) typename std::enable_if< detail::path_traits::is_path_source< typename std::remove_cv< Source >::type >::value, path& - >::type concat(Source const& source) + >::type +#else + path& +#endif + concat(Source const& source) { detail::path_traits::dispatch(source, concat_op(*this)); return *this; } + //! \cond template< typename Source > typename std::enable_if< detail::conjunction< @@ -648,23 +1037,39 @@ class path : detail::path_traits::dispatch_convertible(source, concat_op(*this)); return *this; } - - path& concat(path const& p, codecvt_type const&) - { - m_pathname.append(p.m_pathname); - return *this; - } - + //! \endcond + + /*! + * \brief Concatinates characters from \a source to the end of the path. + * + * **Effects:** Concatenates the characters from \a source to the end of `*this`. Uses \a cvt facet + * to perform character code conversion, if needed. + * + * **Throws:** `std::bad_alloc` on memory allocation failure, `boost::system::system_error` in case + * of character code conversion errors. + * + * \param source Path source to concatenate to the path object. + * \param cvt Character code conversion facet. + * \returns `*this`. + * + * \pre \a source is a valid path source. + */ template< typename Source > +#if !defined(BOOST_FILESYSTEM_DOXYGEN) typename std::enable_if< detail::path_traits::is_path_source< typename std::remove_cv< Source >::type >::value, path& - >::type concat(Source const& source, codecvt_type const& cvt) + >::type +#else + path& +#endif + concat(Source const& source, codecvt_type const& cvt) { detail::path_traits::dispatch(source, concat_op(*this), &cvt); return *this; } + //! \cond template< typename Source > typename std::enable_if< detail::conjunction< @@ -684,14 +1089,31 @@ class path : return *this; } + path& concat(const value_type* begin, const value_type* end, codecvt_type const&) + { + m_pathname.append(begin, end); + return *this; + } + //! \endcond + + /*! + * \brief Concatinates characters from the iterator range to the end of the path. + * + * \returns `concat(begin, end, path::codecvt())`. + */ template< typename InputIterator > +#if !defined(BOOST_FILESYSTEM_DOXYGEN) typename std::enable_if< detail::conjunction< detail::path_traits::is_path_source_iterator< InputIterator >, detail::negation< detail::path_traits::is_native_char_ptr< InputIterator > > >::value, path& - >::type concat(InputIterator begin, InputIterator end) + >::type +#else + path& +#endif + concat(InputIterator begin, InputIterator end) { if (begin != end) { @@ -700,21 +1122,35 @@ class path : } return *this; } - - path& concat(const value_type* begin, const value_type* end, codecvt_type const&) - { - m_pathname.append(begin, end); - return *this; - } - + /*! + * \brief Concatinates characters from the iterator range to the end of the path. + * + * **Effects:** Concatenates a range of characters denoted by \a begin and \a end to the end of `*this`. + * Uses \a cvt facet to perform character code conversion, if needed. + * + * **Throws:** `std::bad_alloc` on memory allocation failure, `boost::system::system_error` in case + * of character code conversion errors. + * + * \param begin Iterator pointing to the beginning of the range of characters to concatenate to the path. + * \param end Iterator pointing to the end of the range of characters to concatenate to the path. + * \param cvt Character code conversion facet. + * \returns `*this`. + * + * \pre `[begin, end)` is a valid range of path characters. + */ template< typename InputIterator > +#if !defined(BOOST_FILESYSTEM_DOXYGEN) typename std::enable_if< detail::conjunction< detail::path_traits::is_path_source_iterator< InputIterator >, detail::negation< detail::path_traits::is_native_char_ptr< InputIterator > > >::value, path& - >::type concat(InputIterator begin, InputIterator end, codecvt_type const& cvt) + >::type +#else + path& +#endif + concat(InputIterator begin, InputIterator end, codecvt_type const& cvt) { if (begin != end) { @@ -724,34 +1160,104 @@ class path : return *this; } - // ----- appends ----- + //! @} + + //! \name appending + //! @{ // if a separator is added, it is the preferred separator for the platform; // slash for POSIX, backslash for Windows + /*! + * \brief Appends \a p to the end of the path. + * + * \returns `append(p)`. + */ path& operator/=(path const& p); + /*! + * \brief Appends \a p to the end of the path. + * + * **Effects:** + * + * **v3:** Concatenates `path::preferred_separator` to `*this`, converting format and encoding if required, unless: + * + * \li an added separator would be redundant, or + * \li would change a relative path to an absolute path, or + * \li `p.empty()`, or + * \li `*p.native().cbegin()` is a directory separator. + * + * Then concatenates `p.native()` to `*this`. + * + * **v4:** If `p.is_absolute() || (p.has_root_name() && p.root_name() != this->root_name())`, assigns `p` to `*this`. + * Otherwise, modifies `*this` as if by these steps: + * + * \li If `p.has_root_directory()`, removes root directory and relative path, if any. + * \li Let `x` be a `path` with contents of `p` without a root name. If `this->has_filename()` is `true` and `x` + * does not start with a directory separator, concatenates `path::preferred_separator`. + * \li Concatenates `x.native()`. + * + * \note Whether the path is absolute or not depends on the target OS conventions. Because of this, the result of + * append operation may be different for different operating systems for some paths. For example, + * `path("//net/foo") / "/bar"` will result in `"/bar"` on POSIX systems and `"//net/foo/bar"` on Windows + * because `"/bar"` is an absolute path on POSIX systems but not on Windows. For portable behavior avoid + * appending paths with non-empty root path. + * + * **Throws:** `std::bad_alloc` on memory allocation failure. + * + * \param p Path to append. + * \returns `*this`. + */ + path& append(path const& p); + /*! + * \brief Appends \a p to the end of the path. + * + * \returns `append(p)`. + * + * \note The \a cvt character code conversion facet is unused and provided for historical reasons, + * for signature compatibility with overloads performing character code conversion. + */ + path& append(path const& p, codecvt_type const&); + /*! + * \brief Appends \a source to the end of the path. + * + * \returns `append(path(source))`. + */ template< typename Source > +#if !defined(BOOST_FILESYSTEM_DOXYGEN) BOOST_FORCEINLINE typename std::enable_if< detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >::value, path& - >::type operator/=(Source const& source) + >::type +#else + path& +#endif + operator/=(Source const& source) { return append(source); } - path& append(path const& p); - + /*! + * \brief Appends \a source to the end of the path. + * + * \returns `append(path(source))`. + */ template< typename Source > +#if !defined(BOOST_FILESYSTEM_DOXYGEN) BOOST_FORCEINLINE typename std::enable_if< detail::path_traits::is_path_source< typename std::remove_cv< Source >::type >::value, path& - >::type append(Source const& source) + >::type +#else + path& +#endif + append(Source const& source) { detail::path_traits::dispatch(source, append_op(*this)); return *this; } + //! \cond template< typename Source > BOOST_FORCEINLINE typename std::enable_if< detail::conjunction< @@ -764,19 +1270,29 @@ class path : detail::path_traits::dispatch_convertible(source, append_op(*this)); return *this; } + //! \endcond - path& append(path const& p, codecvt_type const&); - + /*! + * \brief Appends \a source to the end of the path. + * + * \returns `append(path(source, cvt))`. + */ template< typename Source > +#if !defined(BOOST_FILESYSTEM_DOXYGEN) BOOST_FORCEINLINE typename std::enable_if< detail::path_traits::is_path_source< typename std::remove_cv< Source >::type >::value, path& - >::type append(Source const& source, codecvt_type const& cvt) + >::type +#else + path& +#endif + append(Source const& source, codecvt_type const& cvt) { detail::path_traits::dispatch(source, append_op(*this), &cvt); return *this; } + //! \cond template< typename Source > BOOST_FORCEINLINE typename std::enable_if< detail::conjunction< @@ -791,50 +1307,253 @@ class path : } path& append(const value_type* begin, const value_type* end); + path& append(const value_type* begin, const value_type* end, codecvt_type const&); + //! \endcond + /*! + * \brief Appends characters from the iterator range to the end of the path. + * + * \returns `append(path(begin, end))`. + */ template< typename InputIterator > +#if !defined(BOOST_FILESYSTEM_DOXYGEN) BOOST_FORCEINLINE typename std::enable_if< detail::conjunction< detail::path_traits::is_path_source_iterator< InputIterator >, detail::negation< detail::path_traits::is_native_char_ptr< InputIterator > > >::value, path& - >::type append(InputIterator begin, InputIterator end) + >::type +#else + path& +#endif + append(InputIterator begin, InputIterator end) { std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source(begin, end); detail::path_traits::dispatch(source, append_op(*this)); return *this; } - path& append(const value_type* begin, const value_type* end, codecvt_type const&); - + /*! + * \brief Appends characters from the iterator range to the end of the path. + * + * \returns `append(path(begin, end, cvt))`. + */ template< typename InputIterator > +#if !defined(BOOST_FILESYSTEM_DOXYGEN) BOOST_FORCEINLINE typename std::enable_if< detail::conjunction< detail::path_traits::is_path_source_iterator< InputIterator >, detail::negation< detail::path_traits::is_native_char_ptr< InputIterator > > >::value, path& - >::type append(InputIterator begin, InputIterator end, const codecvt_type& cvt) + >::type +#else + path& +#endif + append(InputIterator begin, InputIterator end, const codecvt_type& cvt) { std::basic_string< typename std::iterator_traits< InputIterator >::value_type > source(begin, end); detail::path_traits::dispatch(source, append_op(*this), &cvt); return *this; } - // ----- modifiers ----- + //! @} + //! \name modifiers + //! @{ + + /*! + * \brief Clears the path. + * + * **Throws:** Nothing. + * + * \post `this->empty() == true`. + */ void clear() noexcept { m_pathname.clear(); } + + /*! + * \brief Converts directory separators to `path::preferred_separator`. + * + * \returns `*this`. + */ path& make_preferred(); + + /*! + * \brief Removes the trailing filename. + * + * **Effects:** + * + * **v3:** As if `*this = parent_path()`. + * + * \note This function is needed to efficiently implement `directory_iterator`. It is exposed + * to allow additional uses. The actual implementation may be much more efficient than + * `*this = parent_path()`. + * + * **v4:** Removes the `filename()` path element. + * + * \note Unlike **v3**, the trailing directory separator(s) are not removed. + * + * \returns `*this`. + */ path& remove_filename(); + + /*! + * \brief Removes the trailing filename and directory separator. + * + * **Effects:** As if `*this = parent_path()`. + * + * \note This function is similar to `path::remove_filename` from **v3**, but is also usable in **v4**. + * + * \returns `*this`. + */ BOOST_FILESYSTEM_DECL path& remove_filename_and_trailing_separators(); + + /*! + * \brief Removes the trailing directory separator. + * + * **Effects:** If `*this` ends with a directory separator, removes that separator. Otherwise, keeps + * `*this` unmodified. + * + * \returns `*this`. + */ BOOST_FILESYSTEM_DECL path& remove_trailing_separator(); + + /*! + * \brief Replaces the trailing filename. + * + * **Effects:** As if `remove_filename().append(replacement)`. + * + * \param replacement The replacement filename. + * \returns `*this`. + * + * **See Also:** \ref path::remove_filename, \ref path::append. + */ BOOST_FILESYSTEM_DECL path& replace_filename(path const& replacement); + + /*! + * \brief Replaces extension in the trailing filename. + * + * **Effects:** + * + * \li Any existing `extension()` is removed from the stored path, then + * \li iff \a new_extension is not empty and does not begin with a dot character, a dot character + * is concatenated to the stored path, then + * \li \a new_extension is concatenated to the stored path. + * + * \param new_extension The replacement extension. + * \returns `*this`. + */ path& replace_extension(path const& new_extension = path()); + /*! + * \brief Swaps `*this` and \a rhs path objects. + * + * **Throws:** Nothing. + * + * \param rhs Path object to swap with. + */ void swap(path& rhs) noexcept { m_pathname.swap(rhs.m_pathname); } - // ----- observers ----- + //! @} + + //! \name observers + //! @{ + + /*! + * \returns `true` if the path is empty and `false` otherwise. + * + * **Throws:** Nothing. + */ + bool empty() const noexcept { return m_pathname.empty(); } + + /*! + * \returns `filename() == path(".")`. + * + * **Example:** + * + * \code + * std::cout << path(".").filename_is_dot(); // outputs 1 + * std::cout << path("/.").filename_is_dot(); // outputs 1 + * std::cout << path("foo/.").filename_is_dot(); // outputs 1 + * std::cout << path("foo/").filename_is_dot(); // v3 outputs 1, v4 outputs 0 + * std::cout << path("/").filename_is_dot(); // outputs 0 + * std::cout << path("/foo").filename_is_dot(); // outputs 0 + * std::cout << path("/foo.").filename_is_dot(); // outputs 0 + * std::cout << path("..").filename_is_dot(); // outputs 0 + * \endcode + * + * See the last bullet item in the path iterators forward traversal order + * list for why `path("foo/").filename()` is a dot filename in **v3**. + */ + bool filename_is_dot() const; + + /*! + * \returns `filename() == path("..")`. + */ + bool filename_is_dot_dot() const; + + /*! + * \returns `! root_path().empty()`. + */ + bool has_root_path() const { return detail::path_algorithms::find_root_path_size(*this) > 0; } + + /*! + * \returns `! root_name().empty()`. + */ + bool has_root_name() const { return detail::path_algorithms::find_root_name_size(*this) > 0; } + + /*! + * \returns `! root_directory().empty()`. + */ + bool has_root_directory() const { return detail::path_algorithms::find_root_directory(*this).size > 0; } + + /*! + * \returns `! relative_path().empty()`. + */ + bool has_relative_path() const { return detail::path_algorithms::find_relative_path(*this).size > 0; } + + /*! + * \returns `! parent_path().empty()`. + */ + bool has_parent_path() const { return detail::path_algorithms::find_parent_path_size(*this) > 0; } + + /*! + * \returns `! filename().empty()`. + */ + bool has_filename() const; + + /*! + * \returns `! stem().empty()`. + */ + bool has_stem() const { return !stem().empty(); } + + /*! + * \returns `! extension().empty()`. + */ + bool has_extension() const { return !extension().empty(); } + + /*! + * \returns `! is_absolute()`. + */ + bool is_relative() const { return !is_absolute(); } + + /*! + * \returns `true` if the elements of `root_path()` uniquely identify a directory, else `false`. + * + * \note On POSIX systems, a path is considered absolute if it has a `[root-directory]`, + * and on Windows - if it has both `[root-name]` and `[root-directory]`. + * + * **See Also:** \ref path::root_path, \ref path::root_name, \ref path::root_directory. + */ + bool is_absolute() const + { +#if defined(BOOST_WINDOWS_API) + return has_root_name() && has_root_directory(); +#else + return has_root_directory(); +#endif + } // For operating systems that format file paths differently than directory // paths, return values from observers are formatted as file names unless there @@ -855,17 +1574,60 @@ class path : // ----- native format observers ----- + /*! + * \returns The pathname in the native format. + */ string_type const& native() const noexcept { return m_pathname; } + /*! + * \returns `native().c_str()`. + */ const value_type* c_str() const noexcept { return m_pathname.c_str(); } + /*! + * \returns `native().size()`. + */ string_type::size_type size() const noexcept { return m_pathname.size(); } + /*! + * \returns `string< String >(codecvt())`. + */ template< typename String > String string() const; + /*! + * \pre `String` is a specialization of `std::basic_string` for one of the path character types. + * + * **Throws:** `std::bad_alloc` on memory allocation failure, `boost::system::system_error` in case + * of character code conversion errors. + * + * \param cvt Character code conversion facet. + * \returns Pathname returned by `native()`. If `string_type` is different from `String`, performs character + * encoding conversion using \a cvt. + */ template< typename String > String string(codecvt_type const& cvt) const; -#ifdef BOOST_WINDOWS_API +#if defined(BOOST_FILESYSTEM_DOXYGEN) + + /*! + * \returns `string< std::string >()`. + */ + std::string string() const; + /*! + * \returns `string< std::string >(cvt)` + */ + std::string string(codecvt_type const& cvt) const; + + /*! + * \returns `string< std::wstring >()`. + */ + std::wstring wstring() const; + /*! + * \returns `string< std::wstring >(cvt)`. + */ + std::wstring wstring(codecvt_type const& cvt) const; + +#elif defined(BOOST_WINDOWS_API) + std::string string() const { std::string tmp; @@ -873,6 +1635,7 @@ class path : detail::path_traits::convert(m_pathname.data(), m_pathname.data() + m_pathname.size(), tmp); return tmp; } + std::string string(codecvt_type const& cvt) const { std::string tmp; @@ -884,7 +1647,9 @@ class path : // string_type is std::wstring, so there is no conversion std::wstring const& wstring() const { return m_pathname; } std::wstring const& wstring(codecvt_type const&) const { return m_pathname; } -#else // BOOST_POSIX_API + +#else + // string_type is std::string, so there is no conversion std::string const& string() const { return m_pathname; } std::string const& string(codecvt_type const&) const { return m_pathname; } @@ -896,6 +1661,7 @@ class path : detail::path_traits::convert(m_pathname.data(), m_pathname.data() + m_pathname.size(), tmp); return tmp; } + std::wstring wstring(codecvt_type const& cvt) const { std::wstring tmp; @@ -903,6 +1669,7 @@ class path : detail::path_traits::convert(m_pathname.data(), m_pathname.data() + m_pathname.size(), tmp, &cvt); return tmp; } + #endif // ----- generic format observers ----- @@ -910,32 +1677,80 @@ class path : // Experimental generic function returning generic formatted path (i.e. separators // are forward slashes). Motivation: simpler than a family of generic_*string // functions. + /*! + * \returns The pathname in the generic format. + */ path generic_path() const; + /*! + * \returns `generic_string< String >(codecvt())`. + */ template< typename String > String generic_string() const; + /*! + * \pre `String` is a specialization of `std::basic_string` for one of the path character types. + * + * **Throws:** `std::bad_alloc` on memory allocation failure, `boost::system::system_error` in case + * of character code conversion errors. + * + * \param cvt Character code conversion facet. + * \returns Pathname returned by `generic_path()`. If `string_type` is different from `String`, performs + * character encoding conversion using \a cvt. + */ template< typename String > String generic_string(codecvt_type const& cvt) const; + /*! + * \returns `generic_string< std::string >()`. + */ std::string generic_string() const { return generic_path().string(); } + /*! + * \returns `generic_string< std::string >(cvt)`. + */ std::string generic_string(codecvt_type const& cvt) const { return generic_path().string(cvt); } + /*! + * \returns `generic_string< std::wstring >()`. + */ std::wstring generic_wstring() const { return generic_path().wstring(); } + /*! + * \returns `generic_string< std::wstring >(cvt)`. + */ std::wstring generic_wstring(codecvt_type const& cvt) const { return generic_path().wstring(cvt); } - // ----- compare ----- + //! @} + + //! \name comparison + //! @{ - int compare(path const& p) const; // generic, lexicographical + /*! + * \returns A value less than 0 if the elements of `*this` are lexicographically less than the elements of \a p, + * otherwise a value greater than 0 if the elements of `*this` are lexicographically greater than + * the elements of \a p, otherwise 0. + * + * \remark The elements are determined as if by iteration over the half-open range [`begin()`, `end()`) for + * `*this` and \a p. + */ + int compare(path const& p) const; + /*! + * \returns `compare(path(source))`. + */ template< typename Source > +#if !defined(BOOST_FILESYSTEM_DOXYGEN) BOOST_FORCEINLINE typename std::enable_if< detail::path_traits::is_path_source< typename std::remove_cv< Source >::type >::value, int - >::type compare(Source const& source) const + >::type +#else + int +#endif + compare(Source const& source) const { return detail::path_traits::dispatch(source, compare_op(*this)); } + //! \cond template< typename Source > BOOST_FORCEINLINE typename std::enable_if< detail::conjunction< @@ -947,16 +1762,26 @@ class path : { return detail::path_traits::dispatch_convertible(source, compare_op(*this)); } + //! \endcond + /*! + * \returns `compare(path(source, cvt))`. + */ template< typename Source > +#if !defined(BOOST_FILESYSTEM_DOXYGEN) BOOST_FORCEINLINE typename std::enable_if< detail::path_traits::is_path_source< typename std::remove_cv< Source >::type >::value, int - >::type compare(Source const& source, codecvt_type const& cvt) const + >::type +#else + int +#endif + compare(Source const& source, codecvt_type const& cvt) const { return detail::path_traits::dispatch(source, compare_op(*this), &cvt); } + //! \cond template< typename Source > BOOST_FORCEINLINE typename std::enable_if< detail::conjunction< @@ -968,14 +1793,26 @@ class path : { return detail::path_traits::dispatch_convertible(source, compare_op(*this), &cvt); } + //! \endcond - // ----- decomposition ----- + //! @} + //! \name decomposition + //! @{ + + /*! + * \returns `root_name() / root_path()`. + */ path root_path() const { return path(m_pathname.c_str(), m_pathname.c_str() + detail::path_algorithms::find_root_path_size(*this)); } - // returns 0 or 1 element path even on POSIX, root_name() is non-empty() for network paths + + /*! + * \returns `[root-name]`, if the path in the generic format includes a `[root-name]`, otherwise `path()`. + */ path root_name() const { return path(m_pathname.c_str(), m_pathname.c_str() + detail::path_algorithms::find_root_name_size(*this)); } - // returns 0 or 1 element path + /*! + * \returns `[root-directory]`, if the path in the generic format includes a `[root-directory]`, otherwise `path()`. + */ path root_directory() const { detail::path_algorithms::substring root_dir = detail::path_algorithms::find_root_directory(*this); @@ -983,6 +1820,10 @@ class path : return path(p, p + root_dir.size); } + /*! + * \returns A `path` composed of the path elements starting with the first `[filename]` after `root_path()`. + * Returns `path()` if there are no such path elements. + */ path relative_path() const { detail::path_algorithms::substring rel_path = detail::path_algorithms::find_relative_path(*this); @@ -990,56 +1831,211 @@ class path : return path(p, p + rel_path.size); } + /*! + * \returns `(empty() || begin() == --end()) ? path() : pp`, where `pp` is constructed as if by + * starting with an empty `path` and successively applying `operator/=` for each element in + * the range [`begin()`, `--end()`). + * + * **Example:** + * + * \code + * std::cout << path("/foo/bar.txt").parent_path(); // outputs "/foo" + * std::cout << path("/foo/bar").parent_path(); // outputs "/foo" + * std::cout << path("/foo/bar/").parent_path(); // outputs "/foo/bar" + * std::cout << path("/").parent_path(); // outputs "" + * std::cout << path(".").parent_path(); // outputs "" + * std::cout << path("..").parent_path(); // outputs "" + * \endcode + * + * See the last bullet item in the path iterators forward traversal order list + * for why the `"/foo/bar/"` example doesn't output `"/foo"`. + */ path parent_path() const { return path(m_pathname.c_str(), m_pathname.c_str() + detail::path_algorithms::find_parent_path_size(*this)); } + /*! + * \returns **v3:** `empty() ? path() : *--end()`.
+ * **v4:** `*this == root_path() ? path() : *--end()`. + * + * **Example:** + * + * \code + * std::cout << path("/foo/bar.txt").filename(); // outputs "bar.txt" + * std::cout << path("/foo/bar").filename(); // outputs "bar" + * std::cout << path("/foo/bar/").filename(); // v3 outputs "." + * // v4 outputs "" + * std::cout << path("/").filename(); // v3 outputs "/" + * // v4 outputs "" + * std::cout << path(".").filename(); // outputs "." + * std::cout << path("..").filename(); // outputs ".." + * \endcode + * + * See the last bullet item in the path iterators forward traversal order list + * for why the `"/foo/bar/"` example doesn't output `"bar"`. + */ path filename() const; // returns 0 or 1 element path - path stem() const; // returns 0 or 1 element path - path extension() const; // returns 0 or 1 element path - // ----- query ----- - - bool empty() const noexcept { return m_pathname.empty(); } - bool filename_is_dot() const; - bool filename_is_dot_dot() const; - bool has_root_path() const { return detail::path_algorithms::find_root_path_size(*this) > 0; } - bool has_root_name() const { return detail::path_algorithms::find_root_name_size(*this) > 0; } - bool has_root_directory() const { return detail::path_algorithms::find_root_directory(*this).size > 0; } - bool has_relative_path() const { return detail::path_algorithms::find_relative_path(*this).size > 0; } - bool has_parent_path() const { return detail::path_algorithms::find_parent_path_size(*this) > 0; } - bool has_filename() const; - bool has_stem() const { return !stem().empty(); } - bool has_extension() const { return !extension().empty(); } - bool is_relative() const { return !is_absolute(); } - bool is_absolute() const - { -#if defined(BOOST_WINDOWS_API) - return has_root_name() && has_root_directory(); -#else - return has_root_directory(); -#endif - } + /*! + * \returns If `p.filename()` does not contain dots, consist solely of one or to two dots, + * [Since v4: or contains exactly one dot as the initial character,] + * returns `p.filename()`. Otherwise returns the substring of `p.filename()` starting at + * its beginning and ending at the last dot (the dot is not included). + * + * **Example:** + * + * \code + * std::cout << path("/foo/bar.txt").stem() << '\\n'; // outputs "bar" + * std::cout << path(".hidden").stem() << '\\n'; // v3 outputs "" + * // v4 outputs ".hidden" + * path p = "foo.bar.baz.tar"; + * for (; !p.extension().empty(); p = p.stem()) // outputs: .tar + * std::cout << p.extension() << '\\n'; // .baz + * // .bar + * \endcode + */ + path stem() const; // returns 0 or 1 element path - // ----- lexical operations ----- + /*! + * \returns The substring of `p.filename()` that is not included in `p.stem()`. + * + * \remark Implementations are permitted but not required to define additional behavior + * for file systems which append additional elements to extensions, such as + * alternate data streams or partitioned dataset names. + * + * **Example:** + * + * \code + * std::cout << path("/foo/bar.txt").extension(); // outputs ".txt" + * \endcode + * + * \note The dot is included in the return value so that it is possible to distinguish + * between no extension and an empty extension. See + * https://lists.boost.org/Archives/boost/2010/02/162028.php for more extensive + * rationale. + */ + path extension() const; // returns 0 or 1 element path + //! @} + + //! \name lexical operations + //! @{ + + /*! + * **Overview:** Returns `*this` with redundant current directory ("."), parent directory (".."), and + * directory separator elements removed. + * + * \remark Uses `path::operator/=` to compose the returned path. + * + * \returns `*this` in normal form. + * + * **Example:** + * + * \code + * std::cout << path("foo/./bar/..").lexically_normal() << std::endl; // outputs "foo" + * std::cout << path("foo/.///bar/../").lexically_normal() << std::endl; // v3: outputs "foo/." + * // v4: outputs "foo/" + * \endcode + * + * On Windows, the returned path's directory-separator characters will be backslashes rather than slashes, + * but that does not affect `path` equality. + */ path lexically_normal() const; + + /*! + * **Overview:** Returns `*this` made relative to \a base. Treats empty or identical paths as corner cases, + * not errors. Does not resolve symlinks. Does not first normalize `*this` or \a base. + * + * \remark Uses `std::mismatch(begin(), end(), base.begin(), base.end())` to determine the first mismatched + * element of `*this` and \a base. Uses `operator==()` to determine if elements match. + * + * \param base Base path, relative to which to produce the path. + * \returns + * \parblock + * \li `path()` if the first mismatched element of `*this` is equal to `begin()` or the first mismatched + * element of \a base is equal to `base.begin()`, or + * \li `path(".")` if the first mismatched element of `*this` is equal to `end()` and the first mismatched + * element of \a base is equal to `base.end()`, or + * \li An object of class `path` composed via application of `operator/=(path(".."))` for each element in + * the half-open range [first mismatched element of \a base, `base.end()`), and then application of + * `operator/=` for each element in the half-open range [first mismatched element of `*this`, `end()`). + * \endparblock + * + * **Example:** + * + * \code + * assert(path("/a/d").lexically_relative("/a/b/c") == "../../d"); + * assert(path("/a/b/c").lexically_relative("/a/d") == "../b/c"); + * assert(path("a/b/c").lexically_relative("a") == "b/c"); + * assert(path("a/b/c").lexically_relative("a/b/c/x/y") == "../.."); + * assert(path("a/b/c").lexically_relative("a/b/c") == "."); + * assert(path("a/b").lexically_relative("c/d") == ""); + * \endcode + * + * The above assertions will succeed. On Windows, the returned path's directory-separator characters will be + * backslashes rather than forward slashes, but that does not affect `path` equality. + * + * \note If symlink following semantics are desired, use the operational function `relative()`. + * + * \note If normalization is needed to ensure consistent matching of elements, apply `lexically_normal()` + * to `*this`, \a base, or both. + */ BOOST_FILESYSTEM_DECL path lexically_relative(path const& base) const; + + /*! + * \returns If `lexically_relative(base)` returns a non-empty path, returns that path. Otherwise returns `*this`. + * + * \note If symlink following semantics are desired, use the operational function `relative()`. + * + * \note If normalization is needed to ensure consistent matching of elements, apply `lexically_normal()` + * to `*this`, \a base, or both. + * + * **See Also:** \ref path::lexically_relative. + */ path lexically_proximate(path const& base) const; - // ----- iterators ----- + //! @} + //! \name iterators + //! @{ + + /*! + * \returns An iterator for the first element in forward traversal order. If no elements are present, the end iterator. + */ BOOST_FILESYSTEM_DECL iterator begin() const; + /*! + * \returns The end iterator in the forward traversal order. + */ BOOST_FILESYSTEM_DECL iterator end() const; + /*! + * \returns An iterator for the first element in backward traversal order. If no elements are present, the end iterator. + */ reverse_iterator rbegin() const; + /*! + * \returns The end iterator in the backward traversal order. + */ reverse_iterator rend() const; - // ----- static member functions ----- + //! @} + //! \name locale operations + //! @{ + + /*! + * **Effects:** Stores a copy of \a loc as the imbued `path` locale. + * + * \returns The previous imbued `path` locale. + * + * \remark The initial value of the imbued `path` locale is operating system dependent. It shall be + * a locale with a `codecvt` facet for a `char` string encoding appropriate for the operating + * system. + */ static BOOST_FILESYSTEM_DECL std::locale imbue(std::locale const& loc); + /*! + * \returns The `codecvt` facet for the imbued `path` locale. + */ static BOOST_FILESYSTEM_DECL codecvt_type const& codecvt(); - //--------------------------------------------------------------------------------------// - // class path private members // - //--------------------------------------------------------------------------------------// + //! @} + private: /* * m_pathname has the type, encoding, and format required by the native @@ -1053,12 +2049,47 @@ class path : // slashes NOT converted to backslashes }; +//! \name path appending +//! @{ + +/*! + * \return `lhs.append(rhs)`. + * + * **See Also:** \ref path::append. + */ +BOOST_FORCEINLINE path operator/(path lhs, path const& rhs) +{ + lhs.append(rhs); + return lhs; +} + +/*! + * \return `lhs.append(rhs)`. + * + * **See Also:** \ref path::append. + */ +template< typename Source > +#if !defined(BOOST_FILESYSTEM_DOXYGEN) +BOOST_FORCEINLINE typename std::enable_if< + detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >::value, + path +>::type +#else +path +#endif +operator/(path lhs, Source const& rhs) +{ + lhs.append(rhs); + return lhs; +} +//! @} + namespace detail { + BOOST_FILESYSTEM_DECL path const& dot_path(); BOOST_FILESYSTEM_DECL path const& dot_dot_path(); -} // namespace detail -namespace path_detail { +namespace path_impl { //------------------------------------------------------------------------------------// // class path::iterator // @@ -1151,9 +2182,8 @@ class path_reverse_iterator : // yield paths, so provide a path aware version bool lexicographical_compare(path_iterator first1, path_iterator const& last1, path_iterator first2, path_iterator const& last2); -} // namespace path_detail - -using path_detail::lexicographical_compare; +} // namespace path_impl +} // namespace detail //------------------------------------------------------------------------------------// // // @@ -1161,6 +2191,10 @@ using path_detail::lexicographical_compare; // // //------------------------------------------------------------------------------------// +#if !defined(BOOST_FILESYSTEM_DOXYGEN) + +using detail::path_impl::lexicographical_compare; + BOOST_FORCEINLINE bool operator==(path const& lhs, path const& rhs) { return lhs.compare(rhs) == 0; @@ -1335,7 +2369,6 @@ BOOST_FORCEINLINE typename std::enable_if< return rhs.compare(lhs) <= 0; } - // Note: Declared as a template to delay binding to Boost.ContainerHash functions and make the dependency optional template< typename Path > inline typename std::enable_if< @@ -1353,41 +2386,253 @@ inline typename std::enable_if< #endif } -inline void swap(path& lhs, path& rhs) noexcept -{ - lhs.swap(rhs); -} +#else // !defined(BOOST_FILESYSTEM_DOXYGEN) -BOOST_FORCEINLINE path operator/(path lhs, path const& rhs) -{ - lhs.append(rhs); - return lhs; -} +//! \name path comparison +//! @{ +/*! + * \returns `lhs.compare(rhs) == 0`. + * + * **See Also:** \ref path::compare. + */ +bool operator==(path const& lhs, path const& rhs); +/*! + * \returns `lhs.compare(rhs) == 0`. + * + * **See Also:** \ref path::compare. + */ template< typename Source > -BOOST_FORCEINLINE typename std::enable_if< - detail::path_traits::is_convertible_to_path_source< typename std::remove_cv< Source >::type >::value, - path ->::type operator/(path lhs, Source const& rhs) +bool operator==(path const& lhs, Source const& rhs); +/*! + * \returns `rhs.compare(lhs) == 0`. + * + * **See Also:** \ref path::compare. + */ +template< typename Source > +bool operator==(Source const& lhs, path const& rhs); + +/*! + * \returns `lhs.compare(rhs) != 0`. + * + * **See Also:** \ref path::compare. + */ +bool operator!=(path const& lhs, path const& rhs); +/*! + * \returns `lhs.compare(rhs) != 0`. + * + * **See Also:** \ref path::compare. + */ +template< typename Source > +bool operator!=(path const& lhs, Source const& rhs); +/*! + * \returns `rhs.compare(lhs) != 0`. + * + * **See Also:** \ref path::compare. + */ +template< typename Source > +bool operator!=(Source const& lhs, path const& rhs); + +/*! + * \returns `lhs.compare(rhs) < 0`. + * + * **See Also:** \ref path::compare. + */ +bool operator<(path const& lhs, path const& rhs); +/*! + * \returns `lhs.compare(rhs) < 0`. + * + * **See Also:** \ref path::compare. + */ +template< typename Source > +bool operator<(path const& lhs, Source const& rhs); +/*! + * \returns `rhs.compare(lhs) > 0`. + * + * **See Also:** \ref path::compare. + */ +template< typename Source > +bool operator<(Source const& lhs, path const& rhs); + +/*! + * \returns `lhs.compare(rhs) > 0`. + * + * **See Also:** \ref path::compare. + */ +bool operator>(path const& lhs, path const& rhs); +/*! + * \returns `lhs.compare(rhs) > 0`. + * + * **See Also:** \ref path::compare. + */ +template< typename Source > +bool operator>(path const& lhs, Source const& rhs); +/*! + * \returns `rhs.compare(lhs) < 0`. + * + * **See Also:** \ref path::compare. + */ +template< typename Source > +bool operator>(Source const& lhs, path const& rhs); + +/*! + * \returns `lhs.compare(rhs) <= 0`. + * + * **See Also:** \ref path::compare. + */ +bool operator<=(path const& lhs, path const& rhs); +/*! + * \returns `lhs.compare(rhs) <= 0`. + * + * **See Also:** \ref path::compare. + */ +template< typename Source > +bool operator<=(path const& lhs, Source const& rhs); +/*! + * \returns `rhs.compare(lhs) >= 0`. + * + * **See Also:** \ref path::compare. + */ +template< typename Source > +bool operator<=(Source const& lhs, path const& rhs); + +/*! + * \returns `lhs.compare(rhs) >= 0`. + * + * **See Also:** \ref path::compare. + */ +bool operator>=(path const& lhs, path const& rhs); +/*! + * \returns `lhs.compare(rhs) >= 0`. + * + * **See Also:** \ref path::compare. + */ +template< typename Source > +bool operator>=(path const& lhs, Source const& rhs); +/*! + * \returns `lhs.compare(rhs) <= 0`. + * + * **See Also:** \ref path::compare. + */ +template< typename Source > +bool operator>=(Source const& lhs, path const& rhs); + +/*! + * \brief Tests whether the two sequences of path elements are lexicographically equal. + * + * \param first1 Beginning of the first sequence. + * \param last1 End of the first sequence. + * \param first2 Beginning of the second sequence. + * \param last2 End of the second sequence. + * \returns `true` if the sequence of `native()` strings for the elements defined by the half-open range [`first1`, `last1`) is + * lexicographically less than the sequence of `native()` strings for the elements defined by the half-open range + * [`first2`, `last2`). Returns `false` otherwise. + * + * \remark If two sequences have the same number of elements and their corresponding elements are equivalent, then neither sequence + * is lexicographically less than the other. If one sequence is a prefix of the other, then the shorter sequence is + * lexicographically less than the longer sequence. Otherwise, the lexicographical comparison of the sequences yields + * the same result as the comparison of the first corresponding pair of elements that are not equivalent. + * + * \note A `path`-aware `lexicographical_compare` algorithm is provided for historical reasons. + */ +bool lexicographical_compare(path::const_iterator first1, path::const_iterator last1, path::const_iterator first2, path::const_iterator last2); +//! @} + +//! \name path hashing +//! @{ + +/*! + * \brief Computes a hash value for the path. + * + * If for two paths, `p1 == p2` then `hash_value(p1) == hash_value(p2)`. The opposite is not necessarily true. This allows paths + * to be used with Boost.Hash. + * + * \param p The path to compute hash for. + * \returns A hash value for the path \a p. + */ +std::size_t hash_value(path const& p) noexcept; +//! @} + +#endif // !defined(BOOST_FILESYSTEM_DOXYGEN) + +//! \name path swapping +//! @{ + +/*! + * **Effects:** As if `lhs.swap(rhs)`. + * + * **See Also:** \ref path::swap. + */ +inline void swap(path& lhs, path& rhs) noexcept { - lhs.append(rhs); - return lhs; + lhs.swap(rhs); } +//! @} + +//! \name path I/O +//! @{ // inserters and extractors // use boost::io::quoted() to handle spaces in paths // use '&' as escape character to ease use for Windows paths +/*! + * \brief Outputs path representation into an output stream. + * + * **Effects:** + * + * Insert characters into `os` as follows: + * + * \li A double-quote. + * \li Each character in `p.string< std::basic_string< Char > >()`. If the character to be inserted + * is equal to the escape character '&' or a double-quote, as determined by `operator==`, first + * insert the escape character. + * \li A double-quote. + * + * \note The effects ensure that the path can safely round-trip with `operator>>`, even if the path + * contains spaces, double-quotes and '&' characters. + * + * \param os Output stream. + * \param p Path to output. + * \returns `os`. + */ template< typename Char, typename Traits > -inline std::basic_ostream< Char, Traits >& -operator<<(std::basic_ostream< Char, Traits >& os, path const& p) +inline std::basic_ostream< Char, Traits >& operator<<(std::basic_ostream< Char, Traits >& os, path const& p) { return os << boost::io::quoted(p.template string< std::basic_string< Char > >(), static_cast< Char >('&')); } +/*! + * \brief Reads path representation from an input stream. + * + * **Effects:** + * + * Extract characters from `is` as follows: + * + *
    + *
  • If the first character that would be extracted is equal to double-quote, as determined by `operator==`, then:
  • + *
      + *
    • Discard the initial double-quote.
    • + *
    • Save the value and then turn off the `skipws` flag in `is`.
    • + *
    • `p.clear()`.
    • + *
    • Until an unescaped double-quote character is reached or `is.not_good()`, extract characters from `is` and + * concatenate them to `p`, except that if an escape character '&' is reached, ignore it and concatenate + * the next character to `p`.
    • + *
    • Discard the final double-quote character.
    • + *
    • Restore the `skipws` flag to its original value in `is`.
    • + *
    + *
  • Otherwise, for `str` being a string of type `std::basic_string< Char >`, `is >> str; p = str;`.
  • + *
+ * + * \note The effects ensure that the path can safely round-trip with `operator<<`, even if the original path + * contained spaces, double-quotes and '&' characters. + * + * \param is Input stream. + * \param p Path to read into. + * \returns `is`. + */ template< typename Char, typename Traits > -inline std::basic_istream< Char, Traits >& -operator>>(std::basic_istream< Char, Traits >& is, path& p) +inline std::basic_istream< Char, Traits >& operator>>(std::basic_istream< Char, Traits >& is, path& p) { std::basic_string< Char > str; is >> boost::io::quoted(str, static_cast< Char >('&')); @@ -1395,18 +2640,84 @@ operator>>(std::basic_istream< Char, Traits >& is, path& p) return is; } -// name_checks +//! @} + +//! \name path name checks +//! @{ // These functions are holdovers from version 1. It isn't clear they have much // usefulness, or how to generalize them for later versions. +/*! + * \brief Tests if the string can be portably used as a name on POSIX systems. + * + * \param name String to test. + * \returns + * \parblock + * `true` if `!name.empty()` and `name` contains only the characters specified in Portable Filename Character Set + * rules as defined in by POSIX (https://pubs.opengroup.org/onlinepubs/007904975/basedefs/xbd_chap03.html). + * + * The allowed characters are "0-9", "a-z", "A-Z", ".", "_", and "-". + * \endparblock + */ BOOST_FILESYSTEM_DECL bool portable_posix_name(std::string const& name); +/*! + * \brief Tests if the string can be used as a name on Windows. + * + * \param name String to test. + * \returns + * \parblock + * `true` if + * + * \li `!name.empty()`, and + * \li `name` contains only the characters specified by the Windows platform SDK as valid regardless of the file system, and + * \li `name` is "." or ".." or does not end with a trailing space or period. + * + * The allowed characters are anything except `0x0-0x1F`, "<", ">", ":", """, "/", "\\", and "|". + * \endparblock + */ BOOST_FILESYSTEM_DECL bool windows_name(std::string const& name); +/*! + * \brief Tests if the string can be used as a name on most systems. + * + * \param name String to test. + * \returns + * \parblock + * `true` if + * + * \li `windows_name(name)`, and + * \li `portable_posix_name(name)`, and + * \li `name` is "." or "..", or the first character of `name` is not a period or hyphen. + * \endparblock + */ BOOST_FILESYSTEM_DECL bool portable_name(std::string const& name); +/*! + * \brief Tests if the string can be used as a directory name on most systems. + * + * \param name String to test. + * \returns `true` if `portable_name(name)` and `name` is "." or ".." or contains no periods. + */ BOOST_FILESYSTEM_DECL bool portable_directory_name(std::string const& name); +/*! + * \brief Tests if the string can be used as a file name on most systems. + * + * \param name String to test. + * \returns `portable_name(name)`, and any period is followed by one to three additional non-period characters. + */ BOOST_FILESYSTEM_DECL bool portable_file_name(std::string const& name); +/*! + * \brief Tests if the string can be considered as a valid name for the native file system. + * + * \returns Returns `true` for names considered valid by the operating system's native file systems. The actual + * criteria for validity are implementation-defined. + * + * \note May return `true` for some names not considered valid by the operating system under all conditions + * (particularly on operating systems which support multiple file systems.) + */ BOOST_FILESYSTEM_DECL bool native(std::string const& name); +//! @} + namespace detail { // For POSIX, is_directory_separator() and is_element_separator() are identical since @@ -1472,6 +2783,8 @@ inline void path_algorithms::append_v4(path& left, path const& right) } // namespace detail +#if !defined(BOOST_FILESYSTEM_DOXYGEN) + // Note: Because of the range constructor in C++23 std::string_view that involves a check for contiguous_range concept, // any non-template function call that requires a check whether the source argument (which may be fs::path) // is convertible to std::string_view must be made after fs::path::iterator is defined. This includes overload @@ -1535,7 +2848,8 @@ inline bool path::filename_is_dot() const inline bool path::filename_is_dot_dot() const { - return size() >= 2 && m_pathname[size() - 1] == dot && m_pathname[size() - 2] == dot && (m_pathname.size() == 2 || detail::is_element_separator(m_pathname[size() - 3])); + return size() >= 2 && m_pathname[size() - 1] == dot && m_pathname[size() - 2] == dot && + (m_pathname.size() == 2 || detail::is_element_separator(m_pathname[size() - 3])); // use detail::is_element_separator() rather than detail::is_directory_separator // to deal with "c:.." edge case on Windows when ':' acts as a separator } @@ -1627,7 +2941,8 @@ BOOST_FORCEINLINE path& path::make_preferred() return *this; } -namespace path_detail { +namespace detail { +namespace path_impl { BOOST_FORCEINLINE void path_iterator::increment() { @@ -1644,7 +2959,8 @@ BOOST_FORCEINLINE bool lexicographical_compare(path_iterator first1, path_iterat return BOOST_FILESYSTEM_VERSIONED_SYM(detail::path_algorithms::lex_compare)(first1, last1, first2, last2) < 0; } -} // namespace path_detail +} // namespace path_impl +} // namespace detail #endif // !defined(BOOST_FILESYSTEM_SOURCE) @@ -1700,6 +3016,8 @@ inline std::wstring path::generic_string< std::wstring >(codecvt_type const& cvt return generic_wstring(cvt); } +#endif // !defined(BOOST_FILESYSTEM_DOXYGEN) + } // namespace filesystem } // namespace boost diff --git a/index.html b/index.html index 3c5ab7640..61f4217d3 100644 --- a/index.html +++ b/index.html @@ -1,10 +1,10 @@ - + Automatic redirection failed, please go to -doc/index.htm. +doc/html/index.html.

© Copyright Beman Dawes, 2003

Distributed under the Boost Software License, Version 1.0. diff --git a/src/path.cpp b/src/path.cpp index 82b2c7d52..714fad9ca 100644 --- a/src/path.cpp +++ b/src/path.cpp @@ -557,8 +557,8 @@ BOOST_FILESYSTEM_DECL void path_algorithms::append_v4(path& p, const value_type* BOOST_FILESYSTEM_DECL int path_algorithms::lex_compare_v3 ( - path_detail::path_iterator first1, path_detail::path_iterator const& last1, - path_detail::path_iterator first2, path_detail::path_iterator const& last2 + path_impl::path_iterator first1, path_impl::path_iterator const& last1, + path_impl::path_iterator first2, path_impl::path_iterator const& last2 ) { for (; first1 != last1 && first2 != last2;) @@ -578,8 +578,8 @@ BOOST_FILESYSTEM_DECL int path_algorithms::lex_compare_v3 BOOST_FILESYSTEM_DECL int path_algorithms::lex_compare_v4 ( - path_detail::path_iterator first1, path_detail::path_iterator const& last1, - path_detail::path_iterator first2, path_detail::path_iterator const& last2 + path_impl::path_iterator first1, path_impl::path_iterator const& last1, + path_impl::path_iterator first2, path_impl::path_iterator const& last2 ) { for (; first1 != last1 && first2 != last2;) @@ -1122,7 +1122,7 @@ namespace boost { namespace filesystem { namespace detail { -BOOST_FILESYSTEM_DECL void path_algorithms::increment_v3(path_detail::path_iterator& it) +BOOST_FILESYSTEM_DECL void path_algorithms::increment_v3(path_impl::path_iterator& it) { const size_type size = it.m_path_ptr->m_pathname.size(); BOOST_ASSERT_MSG(it.m_pos < size, "path::iterator increment past end()"); @@ -1176,7 +1176,7 @@ BOOST_FILESYSTEM_DECL void path_algorithms::increment_v3(path_detail::path_itera it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); } -BOOST_FILESYSTEM_DECL void path_algorithms::increment_v4(path_detail::path_iterator& it) +BOOST_FILESYSTEM_DECL void path_algorithms::increment_v4(path_impl::path_iterator& it) { const size_type size = it.m_path_ptr->m_pathname.size(); BOOST_ASSERT_MSG(it.m_pos <= size, "path::iterator increment past end()"); @@ -1237,7 +1237,7 @@ BOOST_FILESYSTEM_DECL void path_algorithms::increment_v4(path_detail::path_itera it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); } -BOOST_FILESYSTEM_DECL void path_algorithms::decrement_v3(path_detail::path_iterator& it) +BOOST_FILESYSTEM_DECL void path_algorithms::decrement_v3(path_impl::path_iterator& it) { const size_type size = it.m_path_ptr->m_pathname.size(); BOOST_ASSERT_MSG(it.m_pos > 0, "path::iterator decrement past begin()"); @@ -1297,7 +1297,7 @@ BOOST_FILESYSTEM_DECL void path_algorithms::decrement_v3(path_detail::path_itera it.m_element.m_pathname.assign(p + it.m_pos, p + end_pos); } -BOOST_FILESYSTEM_DECL void path_algorithms::decrement_v4(path_detail::path_iterator& it) +BOOST_FILESYSTEM_DECL void path_algorithms::decrement_v4(path_impl::path_iterator& it) { const size_type size = it.m_path_ptr->m_pathname.size(); BOOST_ASSERT_MSG(it.m_pos > 0, "path::iterator decrement past begin()");