// boost/filesystem/directory.hpp ------------------------------------------// // < ----------------------------------------------------------------------- > // < Copyright © 2001 Dietmar Kühl, All Rights Reserved > // < Copyright © 2002 Beman Dawes and Jan Langer. > // < > // < Permission to use, copy, modify, distribute and sell this > // < software for any purpose is hereby granted without fee, provided > // < that the above copyright notice appears in all copies and that > // < both that copyright notice and this permission notice appear in > // < supporting documentation. The authors make no representations about > // < the suitability of this software for any purpose. It is provided > // < "as is" without express or implied warranty. > // < ----------------------------------------------------------------------- > // See http://www.boost.org for most recent version including documentation. //----------------------------------------------------------------------------// #ifndef BOOST_FILESYSTEM_DIRECTORY_HPP #define BOOST_FILESYSTEM_DIRECTORY_HPP #include "boost/smart_ptr.hpp" #include "boost/iterator.hpp" #include "boost/operators.hpp" #include "boost/regex.hpp" // TODO: really need a regex_fwd.hpp #include /* (text parked here pending start of documentation) The filesystem library does not consider directories to be files. Directories cannot portably be opened using the stdio or fstream file facilities. A directory entry, whether identified by a path or by a directory_entry returned by a directory iterator, represents either a file or a directory, never both simultaneously. If an operating system normally views devices, pipes, sockets, connections, or other operating system objects as files (as does POSIX), then these will be treated by the file system library as files, will be found by directory iteration, and can be named in paths. If the operating system does not view such objects as files, the file system library will not treat them as files, directory iteration will not find such objects, and it is invalid to name them in paths except in implementation defined usages. */ //----------------------------------------------------------------------------// // An implementation must provide std::string overloads for the free functions, // and a char specialization for class templates. // // An implementation may provide std::wstring overloads for the free functions, // and wchar_t specializations for class templates. // // An implementation may provide other std::basic_string overloads for the free // functions, and equivalent specializations for class templates. // // Unless otherwise specified: // // * The internal form of path arguments is unspecified. They may represent // either absolute paths, or relative paths if supported by the operating // system. // * Any function may throw if an argument is not well-formed. // * Path arguments of an empty string are not well-formed. // * In addition to the specific "Throws" specified for a function, // all functions will throw if the operating system cannot sucessfully // complete the indicated operation. There is no rollback guarantee; a // failed operation may have altered the state of the external file system. // // Remember that other threads, processes, or computers may have access to a // file system. As an example of the difficulties this can cause, consider // that the following asserts may fail: // // assert( is( "foo" ) == is( "foo" ) ); // remove( "foo" ); // assert( !is( "foo" ) ); // another thread, process, or computer // // may have recreated "foo" after the // // previous call removed "foo". //----------------------------------------------------------------------------// namespace boost { namespace filesystem { // operations on files and directories -------------------------------------// // Where options are provided, the defaults are generally chosen to be // the safest behavior of the alternatives. // TODO: Should there be directory_entry overloads? Some operations might // more efficient if so. // Previous iterations of this header used explictly named functions with // no 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. // Other 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. // Query functions -----------------------------------------------------// // Rationale for providing some attributes via these functions rather // than property map: These are so commonly used that simple syntax and // guaranteed presence outweight other considerations. // Rationale for not providing any multi-attribute named queries: after // several attempts, that was found to be a slippery slope; where do you // stop. See is() below. bool exists( const std::string & path ); // these throw is !exists(path) bool is_directory( const std::string & path ); bool is_file( const std::string & path ); bool is_readonly( const std::string & path ); // as if, !fopen( ..., "a+" ) // TODO: workaround VC++ bug: name clash with boost::is_empty type trait // bool is_empty( const std::string & path ); /* TODO: Decide if is() (see below) is worth the increase in interface complexity. enum flags { existing = 1 << 0, directory = 1 << 1, // directory|file is always false file = 1 << 2, readonly = 1 << 3, // as if, !fopen( ..., "a+" ) empty = 1 << 4 }; // TODO: provide bitmask operations per 17.3.2.1.2 bool is( const std::string & path, flags mask ); // Returns: true if all attributes indicated by mask are true. // Throws: if !(mask&existing) && path does not exist. // Rationale for function: mul */ // options are used to modify the effects of operations ----------------// enum options { none = 0, optional = 1 << 0, // if postconditions are already met on entry, // return without processing effects or throws recurse = 1 << 1, // recurse into sub-directories prune = 1 << 1, // remove directories if and only if empty // There was discussion of providing additional options file_only and // directory_only, which would throw if not as indicated and allow a // bit of additional efficiency, but the benefits were not seen as worth // the added complexity. }; // bitmask operations per 17.3.2.1.2 inline options operator~(options x) { return static_cast(~static_cast(x)); } inline options operator&(options x, options y) { return static_cast(static_cast(x) & static_cast(y)); } inline options operator|(options x, options y) { return static_cast(static_cast(x) | static_cast(y)); } inline options operator^(options x, options y) { return static_cast(static_cast(x) ^ static_cast(y)); } inline options operator&=(options x, options y) { return x = x & y; } inline options operator|=(options x, options y) { return x = x | y; } inline options operator^=(options x, options y) { return x = x ^ y; } // define + too, as it conveys the idea of additive options better that | inline options operator+(options x, options y) { return static_cast(static_cast(x) | static_cast(y)); } inline options operator+=(options x, options y) { return x = x | y; } // operations ----------------------------------------------------------// void create_directory( const std::string & dir_path, options opts=none ); // Postcondition: is_existing_directory( path ) // Throws: if (!(opts&recurse) && (!exists(branch(path)) // || exists(leaf(path)))) || (!(opts&optional) && exists(path)) void remove( const std::string & path, options opts=none ); // Postcondition: !exists( path ); // Throws: if !(opts&optional) && !exists(path) void remove( const std::string & path, const boost::regex & name_filter, options opts=none ); // Postcondition: !exists(itr->path()), for each value of // directory_iterator itr(path) != directory_iterator() where // regex_match( itr->name(), name_filter ) is true. Also applies // to sub-directories, if opts&recurse. // Throws: if !(opts&optional) && !exists(path) // Rationale for regex based interface: believed to be the // most commonly needed and widely useful of several candidates. /* Additional functions were considered (see remove examples below), but rejected as costing too much in terms of interface fat, yet reasonably easy for the user to code directly if needed. void remove( const std::string & path, const std::string & name_filter, options opts=none ); template void remove( const std::string & path, Predicate name_filter, options opts=none ); */ void move( const std::string & old_path, const std::string new_path ); // Effects: Renames the file or directory represented by old_path // to new_path. // Throws: if !exists( old_path ) || exists( new_path ). // Note: Move and rename are the same operation. // Rationale for "move" name: Somewhat clearer than "rename" when an // entity is being moved to a different directory. // TODO: what is effect of move( "/a/b/c", "/d/e" ) if "/d" doesn't // exist? Possibilities: // if !exist( branch( new_path ) ) // throw ... // if !exist( branch( new_path ) ) // create_directory( branch( new_path ), recurse ); template< typename CharT > std::basic_string initial_directory(); // Effects: The first time called, stores an absolute directory path. // The path is determined: // If possible, the path of the initial working directory when main() // was called. Otherwise, if possible, the current working directory. // Otherwise, if possible, a reasonable directory (such as the root // directory on a single rooted filesystem). Otherwise, if possible, // compile or link error. Otherwise, throws an exception. // Returns: The stored path. // Rationale for not simply specifying the return as "initial working // directory when main() was called": That directory isn't known on all // platforms; indeed there may not even be a concept of "current working // directory". The semantics are chosen to come as close to that as // possible (and encourage but not require language runtime support). // Note: It would be good practice in a program dependent on // initial_directory() to call it immediately on entering main(). // That protects against a called function altering the current working // directory (using a native platform function) and then calling // initial_directory(). #if !defined(BOOST_NO_STD_WSTRING) && !defined(BOOST_NO_WIDE_FILESYSTEM) // std::wstring overloads ----------------------------------------------// // TODO: complete this section ... #endif // BOOST_NO_STD_WSTRING // opaque types passed as magic cookies ------------------------------------// namespace detail { template< class CharT > struct basic_dir_itr_rep; template< class CharT > struct basic_dir_entry_rep; } // basic_directory_entry ---------------------------------------------------// template< class CharT > class basic_directory_entry { public: // The semantics of default construction and construction from a path // can't be fully nailed down until the attribute specs are nailed down. // So for now assume the only way to get a useful basic_directory_entry // is by dereferencing a basic_directory_iterator or copy construction. // explicit basic_directory_entry( const std::basic_string & path ); basic_directory_entry(); // users should avoid until specs complete basic_directory_entry( const basic_directory_entry & rhs ); // Effects: deep copy basic_directory_entry & operator=( const basic_directory_entry & rhs ); // Effects: deep copy ~basic_directory_entry(); const std::basic_string & name() const; const std::basic_string & directory_path() const; const std::basic_string & path() const; // Return: compose( directory_path(), name() ) // Rationale for providing path(): makes much common user code simpler. // Rationale for not providing operator== is that it is so difficult // as to be practically impossible (see design docs for details) to // tell if two paths are the same. // There are some implementation details which require access // to the representation. Since it is an opaque type, and thus harmless, // and there are compiler issues with template friends, Dietmar provided // access functions. typedef detail::basic_dir_entry_rep rep_t; rep_t & rep() { return *m_imp; } rep_t const & rep() const { return *m_imp; } private: boost::scoped_ptr m_imp; }; typedef basic_directory_entry directory_entry; #if !defined(BOOST_NO_STD_WSTRING) && !defined(BOOST_NO_WIDE_FILESYSTEM) typedef basic_directory_entry wdirectory_entry; #endif // basic_directory_iterator ------------------------------------------------// // TODO: It might be a considerable convenience to provide either separate // iterators, or else iterator adaptors to do breadth-first and depth-first // recursive directory iteratation. Not needed for initial submission. template< class CharT > class basic_directory_iterator: public boost::iterator< std::input_iterator_tag, basic_directory_entry< CharT > >, public boost::equality_comparable< basic_directory_iterator< CharT > >, public boost::dereferenceable< basic_directory_iterator< CharT >, const basic_directory_entry< CharT > * >, public boost::incrementable< basic_directory_iterator< CharT > > { public: typedef boost::iterator< std::input_iterator_tag, basic_directory_entry > base; typedef typename base::value_type value_type; typedef typename base::difference_type difference_type; typedef typename base::pointer pointer; typedef typename base::reference reference; typedef typename base::iterator_category iterator_category; basic_directory_iterator(); explicit basic_directory_iterator( const std::basic_string & dirpath ); ~basic_directory_iterator(); // compiler generates copy constructor and copy assignment bool operator==( const basic_directory_iterator & ) const; basic_directory_entry const & operator*() const; basic_directory_iterator & operator++ (); private: typedef detail::basic_dir_itr_rep rep_t; boost::shared_ptr m_imp; }; typedef basic_directory_iterator directory_iterator; #if !defined(BOOST_NO_STD_WSTRING) && !defined(BOOST_NO_WIDE_FILESYSTEM) typedef basic_directory_iterator wdirectory_iterator; #endif } // namespace filesystem } // namespace boost #endif // BOOST_FILESYSTEM_DIRECTORY_HPP