From 4768220752619071f3d4d96f7cd881fe1251850b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Lars=20Gullik=20Bj=C3=B8nnes?= Date: Thu, 8 Jan 2004 17:47:56 +0000 Subject: [PATCH] boost::filesystem added git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8328 a592a061-630c-0410-9148-cb99ea01b6c8 --- ChangeLog | 10 +- boost/ChangeLog | 4 + boost/boost/filesystem/convenience.hpp | 38 ++ boost/boost/filesystem/exception.hpp | 105 ++++ boost/boost/filesystem/fstream.hpp | 124 ++++ boost/boost/filesystem/operations.hpp | 121 ++++ boost/boost/filesystem/path.hpp | 213 +++++++ boost/libs/Makefile.am | 2 +- boost/libs/filesystem/.cvsignore | 2 + boost/libs/filesystem/Makefile.am | 4 + boost/libs/filesystem/src/.cvsignore | 6 + boost/libs/filesystem/src/Makefile.am | 13 + boost/libs/filesystem/src/convenience.cpp | 32 + boost/libs/filesystem/src/exception.cpp | 246 ++++++++ .../src/operations_posix_windows.cpp | 484 +++++++++++++++ .../filesystem/src/path_posix_windows.cpp | 566 ++++++++++++++++++ configure.ac | 2 + 17 files changed, 1968 insertions(+), 4 deletions(-) create mode 100644 boost/boost/filesystem/convenience.hpp create mode 100644 boost/boost/filesystem/exception.hpp create mode 100644 boost/boost/filesystem/fstream.hpp create mode 100644 boost/boost/filesystem/operations.hpp create mode 100644 boost/boost/filesystem/path.hpp create mode 100644 boost/libs/filesystem/.cvsignore create mode 100644 boost/libs/filesystem/Makefile.am create mode 100644 boost/libs/filesystem/src/.cvsignore create mode 100644 boost/libs/filesystem/src/Makefile.am create mode 100644 boost/libs/filesystem/src/convenience.cpp create mode 100644 boost/libs/filesystem/src/exception.cpp create mode 100644 boost/libs/filesystem/src/operations_posix_windows.cpp create mode 100644 boost/libs/filesystem/src/path_posix_windows.cpp diff --git a/ChangeLog b/ChangeLog index fcd3a91d96..5e6731f504 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,11 +1,15 @@ +2004-01-08 Lars Gullik Bjonnes + + * configure.ac (AC_CONFIG_FILES): add boost::filesystem Makefiles. + 2003-12-15 Ronald Florence * README.MacOSX: updated for 1.4.0cvs - + 2003-11-18 Angus Leeming * autogen.sh: accept autoconf 2.58 as a supported version. - + 2003-10-24 André Pönitz * lyxfunc.C: @@ -19,7 +23,7 @@ * INSTALL: remove a comment about --with-included-string * configure.ac: remove the configure are - --with-included-string + --with-included-string 2003-09-21 Lars Gullik Bjønnes diff --git a/boost/ChangeLog b/boost/ChangeLog index 624bd12ec6..14b47d2349 100644 --- a/boost/ChangeLog +++ b/boost/ChangeLog @@ -1,3 +1,7 @@ +2004-01-08 Lars Gullik Bjonnes + + * add boost::filesystem. + 2003-10-23 Lars Gullik Bjønnes * libs/regex/src/cpp_regex_traits.cpp (seekpos): use correct diff --git a/boost/boost/filesystem/convenience.hpp b/boost/boost/filesystem/convenience.hpp new file mode 100644 index 0000000000..5a5f428e32 --- /dev/null +++ b/boost/boost/filesystem/convenience.hpp @@ -0,0 +1,38 @@ +// boost/filesystem/convenience.hpp ----------------------------------------// + +// (C) Copyright Beman Dawes, 2002 +// (C) Copyright Vladimir Prus, 2002 +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. + + +// See http://www.boost.org/libs/filesystem for documentation. + +//----------------------------------------------------------------------------// + +#ifndef BOOST_FILESYSTEM_CONVENIENCE_HPP +#define BOOST_FILESYSTEM_CONVENIENCE_HPP + +#include +#include + +namespace boost +{ + namespace filesystem + { + +// create_directories (contributed by Vladimir Prus) -----------------------// + + + /** Creates directory 'ph' and all necessary parent directories. + @post exists(directory_ph) && is_directory(directory_ph) && is_empty(directory_ph) + */ + void create_directories(const path& ph); + + } // namespace filesystem +} // namespace boost +#endif // BOOST_FILESYSTEM_CONVENIENCE_HPP + + diff --git a/boost/boost/filesystem/exception.hpp b/boost/boost/filesystem/exception.hpp new file mode 100644 index 0000000000..8f3c9ebda3 --- /dev/null +++ b/boost/boost/filesystem/exception.hpp @@ -0,0 +1,105 @@ +// boost/filesystem/exception.hpp ------------------------------------------// + +// < ----------------------------------------------------------------------- > +// < Copyright © 2002 Beman Dawes > +// < Copyright © 2001 Dietmar Kühl, All Rights Reserved > +// < > +// < Permission to use, copy, modify, distribute and sell this > +// < software for any purpose is hereby granted without fee, provided > +// < that the above copyright notice appears in all copies and that > +// < both that copyright notice and this permission notice appear in > +// < supporting documentation. The authors make no representations about > +// < the suitability of this software for any purpose. It is provided > +// < "as is" without express or implied warranty. > +// < ----------------------------------------------------------------------- > + +// See http://www.boost.org/libs/filesystem for documentation. + +//----------------------------------------------------------------------------// + +#ifndef BOOST_FILESYSTEM_EXCEPTION_HPP +#define BOOST_FILESYSTEM_EXCEPTION_HPP + +#include + +#include +#include + +//----------------------------------------------------------------------------// + +namespace boost +{ + namespace filesystem + { + namespace detail + { + int system_error_code(); // artifact of POSIX and WINDOWS error reporting + } + + enum error_code + { + no_error = 0, + system_error, // system generated error; if possible, is translated + // to one of the more specific errors below. + other_error, // library generated error + security_error, // includes access rights, permissions failures + read_only_error, + io_error, + path_error, + not_found_error, + not_directory_error, + busy_error, // implies trying again might succeed + already_exists_error, + not_empty_error, + is_directory_error, + out_of_space_error, + out_of_memory_error, + out_of_resource_error + }; + + + class filesystem_error : public std::runtime_error + { + public: + + filesystem_error( + const std::string & who, + const std::string & message ); // assumed to be error_code::other_error + + filesystem_error( + const std::string & who, + const path & path1, + const std::string & message ); // assumed to be error_code::other_error + + filesystem_error( + const std::string & who, + const path & path1, + int sys_err_code ); + + filesystem_error( + const std::string & who, + const path & path1, + const path & path2, + int sys_err_code ); + + ~filesystem_error() throw(); + + int native_error() const { return m_sys_err; } + // Note: a value of 0 implies a library (rather than system) error + error_code error() const { return m_err; } + const std::string & who() const; // name of who throwing exception + const path & path1() const; // argument 1 to who; may be empty() + const path & path2() const; // argument 2 to who; may be empty() + + private: + int m_sys_err; + error_code m_err; + std::string m_who; + path m_path1; + path m_path2; + }; + + } // namespace filesystem +} // namespace boost + +#endif // BOOST_FILESYSTEM_EXCEPTION_HPP diff --git a/boost/boost/filesystem/fstream.hpp b/boost/boost/filesystem/fstream.hpp new file mode 100644 index 0000000000..3c9a4d280d --- /dev/null +++ b/boost/boost/filesystem/fstream.hpp @@ -0,0 +1,124 @@ +// boost/filesystem/fstream.hpp --------------------------------------------// + +// (C) Copyright Beman Dawes 2002. Permission to copy, use, modify, sell and +// distribute this software is granted provided this copyright notice appears +// in all copies. This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. + +// See http://www.boost.org/libs/filesystem for documentation. + +//----------------------------------------------------------------------------// + +#ifndef BOOST_FILESYSTEM_FSTREAM_HPP +#define BOOST_FILESYSTEM_FSTREAM_HPP + +#include + +#include +#include + +namespace boost +{ + namespace filesystem + { + template < class charT, class traits = std::char_traits > + class basic_filebuf : public std::basic_filebuf + { + public: + virtual ~basic_filebuf() {} + +#if !defined(BOOST_MSVC) || BOOST_MSVC > 1200 // VC++ 6.0 can't handle this + std::basic_filebuf * open( const path & file_ph, + std::ios_base::openmode mode ) + { + return std::basic_filebuf::open( + file_ph.native_file_string().c_str(), mode ); + } +#endif + }; + + typedef basic_filebuf filebuf; +# ifndef BOOST_NO_STD_WSTRING + typedef basic_filebuf wfilebuf; +# endif + + template < class charT, class traits = std::char_traits > + class basic_ifstream : public std::basic_ifstream + { + public: + basic_ifstream() {} + explicit basic_ifstream( const path & file_ph, + std::ios_base::openmode mode = std::ios_base::in ) + : std::basic_ifstream( + file_ph.native_file_string().c_str(), mode ) {} + virtual ~basic_ifstream() {} +#if !defined(BOOST_MSVC) || BOOST_MSVC > 1200 // VC++ 6.0 can't handle this + void open( const path & file_ph, + std::ios_base::openmode mode = std::ios_base::in ) + { + std::basic_ifstream::open( + file_ph.native_file_string().c_str(), mode ); + } +#endif + }; + + typedef basic_ifstream ifstream; +# ifndef BOOST_NO_STD_WSTRING + typedef basic_ifstream wifstream; +# endif + + template < class charT, class traits = std::char_traits > + class basic_ofstream : public std::basic_ofstream + { + public: + basic_ofstream() {} + explicit basic_ofstream( const path & file_ph, + std::ios_base::openmode mode = std::ios_base::out ) + : std::basic_ofstream( + file_ph.native_file_string().c_str(), mode ) {} + virtual ~basic_ofstream() {} +#if !defined(BOOST_MSVC) || BOOST_MSVC > 1200 // VC++ 6.0 can't handle this + void open( const path & file_ph, + std::ios_base::openmode mode = std::ios_base::out ) + { + std::basic_ofstream::open( + file_ph.native_file_string().c_str(), mode ); + } +#endif + }; + + typedef basic_ofstream ofstream; +# ifndef BOOST_NO_STD_WSTRING + typedef basic_ofstream wofstream; +# endif + + template < class charT, class traits = std::char_traits > + class basic_fstream : public std::basic_fstream + { + public: + basic_fstream() {} + explicit basic_fstream( const path & file_ph, + std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out ) + : std::basic_fstream( + file_ph.native_file_string().c_str(), mode ) {} + virtual ~basic_fstream() {} +#if !defined(BOOST_MSVC) || BOOST_MSVC > 1200 // VC++ 6.0 can't handle this + void open( const path & file_ph, + std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out ) + { + std::basic_fstream::open( + file_ph.native_file_string().c_str(), mode ); + } +#endif + }; + + typedef basic_fstream fstream; +# ifndef BOOST_NO_STD_WSTRING + typedef basic_fstream wfstream; +# endif + } // namespace filesystem + +} // namespace boost + +#endif // BOOST_FILESYSTEM_FSTREAM_HPP + diff --git a/boost/boost/filesystem/operations.hpp b/boost/boost/filesystem/operations.hpp new file mode 100644 index 0000000000..b5c38b9360 --- /dev/null +++ b/boost/boost/filesystem/operations.hpp @@ -0,0 +1,121 @@ +// boost/filesystem/directory.hpp ------------------------------------------// + +// < ----------------------------------------------------------------------- > +// < Copyright © 2002 Beman Dawes. > +// < Copyright © 2002 Jan Langer. > +// < Copyright © 2001 Dietmar Kühl, All Rights Reserved > +// < > +// < Permission to use, copy, modify, distribute and sell this > +// < software for any purpose is hereby granted without fee, provided > +// < that the above copyright notice appears in all copies and that > +// < both that copyright notice and this permission notice appear in > +// < supporting documentation. The authors make no representations about > +// < the suitability of this software for any purpose. It is provided > +// < "as is" without express or implied warranty. > +// < ----------------------------------------------------------------------- > + +// See http://www.boost.org/libs/filesystem for documentation. + +//----------------------------------------------------------------------------// + +#ifndef BOOST_FILESYSTEM_DIRECTORY_HPP +#define BOOST_FILESYSTEM_DIRECTORY_HPP + +#include +#include +#include +#include + +#include + +//----------------------------------------------------------------------------// + +namespace boost +{ + namespace filesystem + { + +// query functions ---------------------------------------------------------// + + bool exists( const path & ph ); + + bool is_directory( const path & ph ); + + // VC++ 7.0 and earlier has a serious namespace bug that causes a clash + // between boost::filesystem::is_empty and the unrelated type trait + // boost::is_empty. The workaround for those who must use broken versions + // of VC++ is to use the function _is_empty. All others should use the + // correct is_empty name. + bool _is_empty( const path & ph ); // deprecated + +# if !defined( BOOST_MSVC ) || BOOST_MSVC > 1300 + inline bool is_empty( const path & ph ) { return _is_empty( ph ); } +# endif + +// operations --------------------------------------------------------------// + + void create_directory( const path & directory_ph ); + + bool remove( const path & ph ); + unsigned long remove_all( const path & ph ); + + void rename( const path & from_path, + const path & to_path ); + + void copy_file( const path & from_file_ph, + const path & to_file_ph ); + + path current_path(); + const path & initial_path(); + + path system_complete( const path & ph ); + path complete( const path & ph, const path & base = initial_path() ); + +// directory_iterator ------------------------------------------------------// + + class directory_iterator + : public boost::iterator< std::input_iterator_tag, + path, std::ptrdiff_t, const path *, const path & > + { + private: + typedef directory_iterator self; + public: + directory_iterator(); // creates the "end" iterator + explicit directory_iterator( const path & p ); + + reference operator*() const { return m_deref(); } + pointer operator->() const { return &m_deref(); } + self & operator++() { m_inc(); return *this; } + + friend bool operator==( const self & x, const self & y ) + { return x.m_imp == y.m_imp; } + friend bool operator!=( const self & x, const self & y ) + { return !(x.m_imp == y.m_imp); } + + struct path_proxy // allows *i++ to work, as required by std + { + path pv; + explicit path_proxy( const path & p ) : pv(p) {} + path operator*() const { return pv; } + }; + + path_proxy operator++(int) + { + path_proxy pp( m_deref() ); + ++*this; + return pp; + } + + private: + class dir_itr_imp; + // shared_ptr provides shallow-copy semantics required for InputIterators + typedef boost::shared_ptr< dir_itr_imp > m_imp_ptr; + m_imp_ptr m_imp; + reference m_deref() const; + void m_inc(); + }; + + } // namespace filesystem +} // namespace boost + +#endif // BOOST_FILESYSTEM_DIRECTORY_HPP diff --git a/boost/boost/filesystem/path.hpp b/boost/boost/filesystem/path.hpp new file mode 100644 index 0000000000..42e41d540a --- /dev/null +++ b/boost/boost/filesystem/path.hpp @@ -0,0 +1,213 @@ +// boost/filesystem/path.hpp -----------------------------------------------// + +// (C) Copyright Beman Dawes 2002. Permission to copy, use, modify, sell and +// distribute this software is granted provided this copyright notice appears +// in all copies. This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. + + +// See http://www.boost.org/libs/filesystem for documentation. + +//----------------------------------------------------------------------------// + +#ifndef BOOST_FILESYSTEM_PATH_HPP +#define BOOST_FILESYSTEM_PATH_HPP + +#include +#include +#include + +//----------------------------------------------------------------------------// + +namespace boost +{ + namespace filesystem + { + class path; + + namespace detail + { + struct path_itr_imp + { + std::string name; // cache current element. + const path * path_ptr; // path being iterated over. + std::string::size_type pos; // position of name in + // path_ptr->string(). The + // end() iterator is indicated by + // pos == path_ptr->string().size() + + const std::string & operator*() const { return name; } + void operator++(); + void operator--(); + bool operator==( const path_itr_imp & rhs ) const + { return path_ptr == rhs.path_ptr && pos == rhs.pos; } + }; + } // detail + + enum path_format { native }; // ugly enough to discourage use + // except when actually needed + + // path -------------------------------------------------------------------// + + class path + { + public: + // compiler generates copy constructor, copy assignment, and destructor + + path(){} + + path( const std::string & src ); + path( const char * src ); + + path( const std::string & src, path_format ); + path( const char * src, path_format ); + + // append operations: + path & operator /=( const path & rhs ); + path operator /( const path & rhs ) const + { return path( *this ) /= rhs; } + + // conversion functions: + const std::string & string() const { return m_path; } + std::string native_file_string() const; + std::string native_directory_string() const; + + // decomposition functions: + path root_path() const; + std::string root_name() const; + std::string root_directory() const; + path relative_path() const; + std::string leaf() const; + path branch_path() const; + + // query functions: + bool empty() const { return m_path.empty(); } // name consistent with std containers + + bool is_complete() const; + + bool has_root_path() const; + bool has_root_name() const; + bool has_root_directory() const; + bool has_relative_path() const; + bool has_leaf() const { return !m_path.empty(); } + bool has_branch_path() const; + + // iteration over the names in the path: + typedef boost::iterator_adaptor< + detail::path_itr_imp, + boost::default_iterator_policies, + std::string, + const std::string &, + const std::string *, + std::bidirectional_iterator_tag, + std::ptrdiff_t + > iterator; + + iterator begin() const; + iterator end() const + { + iterator itr; + itr.base().path_ptr = this; + itr.base().pos = m_path.size(); + return itr; + } + + private: + // Note: This is an implementation for POSIX and Windows, where there + // are only minor differences between generic and system-specific + // constructor input formats. Private members might be quite different + // in other implementations, particularly where there were wide + // differences between generic and system-specific argument formats, + // or between native_file_string() and native_directory_string() formats. + + std::string m_path; + + friend class directory_iterator; + friend struct boost::filesystem::detail::path_itr_imp; + + enum source_context { generic, platform, nocheck }; + + void m_path_append( const std::string & src, + source_context context = generic ); + + public: // should be private, but friend functions don't work for me + void m_replace_leaf( const char * new_leaf ); + }; + + // path non-member functions ---------------------------------------------// + + inline path operator / ( const char * lhs, const path & rhs ) + { return path( lhs ) /= rhs; } + + inline path operator / ( const std::string & lhs, const path & rhs ) + { return path( lhs ) /= rhs; } + + // error checking --------------------------------------------------------// + +// TODO: write a program that probes valid file and directory names. Ask +// Boost people to report results from many operating systems. Use results +// to adjust generic_name(). + + // generic_name() is extremely permissive; its intent is not to ensure + // general portablity, but rather to detect names so trouble-prone that + // they likely represent coding errors or gross misconceptions. + // + // Any characters are allowed except: + // + // Those characters < ' ', including '\0'. These are the so-called + // control characters, in both ASCII (and its decendents) and EBCDIC. + // Hard to imagine how these could be useful in a generic path name. + // + // < > : " / \ | * ? These have special meaning to enough operating + // systems that use in a generic name would be a serious problem. + // + // The names "." and ".." are not allowed. + // An empty name (null string) is not allowed. + // Names beginning or ending with spaces are not allowed. + // + bool generic_name( const std::string & name ); + + // posix_name() is based on POSIX (IEEE Std 1003.1-2001) + // "Portable Filename Character Set" rules. + // http://www.opengroup.org/onlinepubs/007904975/basedefs/xbd_chap03.html + // + // That character set only allows 0-9, a-z, A-Z, '.', '_', and '-'. + // Note that such names are also portable to other popular operating + // systems, such as Windows. + // + bool posix_name( const std::string & name ); + + const path & check_posix_leaf( const path & ph ); + // Throws: if !posix_name( ph.leaf() ) + // Returns: ph + // Note: Although useful in its own right, check_posix_leaf() also serves + // as an example. A user might provide similar functions; behavior might + // be to assert or warn rather than throw. A user provided function + // could also check the entire path instead of just the leaf; a leaf + // check is often, but not always, the required behavior. + // Rationale: For the "const path &" rather than "void" return is to + // allow (and encourage portability checking) uses like: + // create_directory( check_posix_leaf( "foo" ) ); + // While there is some chance of misuse (by passing through a reference + // to a temporary), the benefits outweigh the costs. + + // For Boost, we often tighten name restrictions for maximum portability: + // + // * The portable POSIX character restrictions, plus + // * Maximum name length 31 characters (for Classic Mac OS). + // * Lowercase only (so code written on case-insensitive platforms like + // Windows works properly when used on case-sensitive systems like + // POSIX. + // * Directory names do not contain '.', as this is not a valid character + // for directory names on some systems. + // + // TODO: provide some check_boost_xxx functions once error handling + // approach ratified. + + bool boost_file_name( const std::string & name ); + bool boost_directory_name( const std::string & name ); + + } // namespace filesystem +} // namespace boost + +#endif // BOOST_FILESYSTEM_PATH_HPP diff --git a/boost/libs/Makefile.am b/boost/libs/Makefile.am index b8bc3cc3e5..d8654749c8 100644 --- a/boost/libs/Makefile.am +++ b/boost/libs/Makefile.am @@ -1,3 +1,3 @@ include $(top_srcdir)/config/common.am -SUBDIRS = regex signals +SUBDIRS = filesystem regex signals diff --git a/boost/libs/filesystem/.cvsignore b/boost/libs/filesystem/.cvsignore new file mode 100644 index 0000000000..282522db03 --- /dev/null +++ b/boost/libs/filesystem/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/boost/libs/filesystem/Makefile.am b/boost/libs/filesystem/Makefile.am new file mode 100644 index 0000000000..c677165dc7 --- /dev/null +++ b/boost/libs/filesystem/Makefile.am @@ -0,0 +1,4 @@ +include $(top_srcdir)/config/common.am + +SUBDIRS = src + diff --git a/boost/libs/filesystem/src/.cvsignore b/boost/libs/filesystem/src/.cvsignore new file mode 100644 index 0000000000..79974082a7 --- /dev/null +++ b/boost/libs/filesystem/src/.cvsignore @@ -0,0 +1,6 @@ +Makefile +Makefile.in +libboostfilesystem.la +*.lo +.libs +.deps diff --git a/boost/libs/filesystem/src/Makefile.am b/boost/libs/filesystem/src/Makefile.am new file mode 100644 index 0000000000..2a42b8f255 --- /dev/null +++ b/boost/libs/filesystem/src/Makefile.am @@ -0,0 +1,13 @@ +include $(top_srcdir)/config/common.am + +noinst_LTLIBRARIES = libboostfilesystem.la + +INCLUDES = $(BOOST_INCLUDES) + +libboostfilesystem_la_SOURCES = \ + convenience.cpp \ + exception.cpp \ + Makefile.am \ + operations_posix_windows.cpp \ + path_posix_windows.cpp + diff --git a/boost/libs/filesystem/src/convenience.cpp b/boost/libs/filesystem/src/convenience.cpp new file mode 100644 index 0000000000..85009213fb --- /dev/null +++ b/boost/libs/filesystem/src/convenience.cpp @@ -0,0 +1,32 @@ +// libs/filesystem/src/convenience.cpp -------------------------------------// + +// (C) Copyright Beman Dawes, 2002 +// (C) Copyright Vladimir Prus, 2002 +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. + +// See http://www.boost.org/libs/filesystem for documentation. + +#include + +namespace boost +{ + namespace filesystem + { + +// create_directories (contributed by Vladimir Prus) -----------------------// + + void create_directories(const path& ph) + { + if (ph.empty() || exists(ph)) return; + + // First create branch, by calling ourself recursively + create_directories(ph.branch_path()); + // Now that parent's path exists, create the directory + create_directory(ph); + } + + } // namespace filesystem +} // namespace boost diff --git a/boost/libs/filesystem/src/exception.cpp b/boost/libs/filesystem/src/exception.cpp new file mode 100644 index 0000000000..9950418617 --- /dev/null +++ b/boost/libs/filesystem/src/exception.cpp @@ -0,0 +1,246 @@ +// Exception implementation file -------------------------------------------// + +// < ----------------------------------------------------------------------- > +// < Copyright © 2002 Beman Dawes > +// < Copyright © 2001 Dietmar Kühl, All Rights Reserved > +// < > +// < Permission to use, copy, modify, distribute and sell this > +// < software for any purpose is hereby granted without fee, provided > +// < that the above copyright notice appears in all copies and that > +// < both that copyright notice and this permission notice appear in > +// < supporting documentation. The authors make no representations about > +// < the suitability of this software for any purpose. It is provided > +// < "as is" without express or implied warranty. > +// < ----------------------------------------------------------------------- > + +// See http://www.boost.org/libs/filesystem for documentation. + +//----------------------------------------------------------------------------// + +#include +#include + +namespace fs = boost::filesystem; + +#include // SGI MIPSpro compilers need this +#include + +# ifdef BOOST_NO_STDC_NAMESPACE + namespace std { using ::strerror; } +# endif + +// BOOST_POSIX or BOOST_WINDOWS specify which API to use. +# if !defined( BOOST_WINDOWS ) && !defined( BOOST_POSIX ) +# if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__) +# define BOOST_WINDOWS +# else +# define BOOST_POSIX +# endif +# endif + +# if defined( BOOST_WINDOWS ) +# include "windows.h" +# else +# include // for POSIX error codes +# endif + +//----------------------------------------------------------------------------// + +namespace +{ + std::string system_message( int sys_err_code ) + { + std::string str; +# ifdef BOOST_WINDOWS + LPVOID lpMsgBuf; + ::FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + sys_err_code, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPSTR) &lpMsgBuf, + 0, + NULL + ); + str += static_cast(lpMsgBuf); + ::LocalFree( lpMsgBuf ); // free the buffer + while ( str.size() + && (str[str.size()-1] == '\n' || str[str.size()-1] == '\r') ) + str.erase( str.size()-1 ); +# else + str += std::strerror( errno ); +# endif + return str; + } + + struct ec_xlate { int sys_ec; fs::error_code ec; }; + const ec_xlate ec_table[] = + { +# ifdef BOOST_WINDOWS + { ERROR_ACCESS_DENIED, fs::security_error }, + { ERROR_INVALID_ACCESS, fs::security_error }, + { ERROR_SHARING_VIOLATION, fs::security_error }, + { ERROR_LOCK_VIOLATION, fs::security_error }, + { ERROR_LOCKED, fs::security_error }, + { ERROR_NOACCESS, fs::security_error }, + { ERROR_WRITE_PROTECT, fs::read_only_error }, + { ERROR_NOT_READY, fs::io_error }, + { ERROR_SEEK, fs::io_error }, + { ERROR_READ_FAULT, fs::io_error }, + { ERROR_WRITE_FAULT, fs::io_error }, + { ERROR_CANTOPEN, fs::io_error }, + { ERROR_CANTREAD, fs::io_error }, + { ERROR_CANTWRITE, fs::io_error }, + { ERROR_DIRECTORY, fs::path_error }, + { ERROR_INVALID_NAME, fs::path_error }, + { ERROR_FILE_NOT_FOUND, fs::not_found_error }, + { ERROR_PATH_NOT_FOUND, fs::not_found_error }, + { ERROR_DEV_NOT_EXIST, fs::not_found_error }, + { ERROR_DEVICE_IN_USE, fs::busy_error }, + { ERROR_OPEN_FILES, fs::busy_error }, + { ERROR_BUSY_DRIVE, fs::busy_error }, + { ERROR_BUSY, fs::busy_error }, + { ERROR_FILE_EXISTS, fs::already_exists_error }, + { ERROR_ALREADY_EXISTS, fs::already_exists_error }, + { ERROR_DIR_NOT_EMPTY, fs::not_empty_error }, + { ERROR_HANDLE_DISK_FULL, fs::out_of_space_error }, + { ERROR_DISK_FULL, fs::out_of_space_error }, + { ERROR_OUTOFMEMORY, fs::out_of_memory_error }, + { ERROR_NOT_ENOUGH_MEMORY, fs::out_of_memory_error }, + { ERROR_TOO_MANY_OPEN_FILES, fs::out_of_resource_error } +# else + { EACCES, fs::security_error }, + { EROFS, fs::read_only_error }, + { EIO, fs::io_error }, + { ENAMETOOLONG, fs::path_error }, + { ENOENT, fs::not_found_error }, + { ENOTDIR, fs::not_directory_error }, + { EAGAIN, fs::busy_error }, + { EBUSY, fs::busy_error }, + { ETXTBSY, fs::busy_error }, + { EEXIST, fs::already_exists_error }, + { ENOTEMPTY, fs::not_empty_error }, + { EISDIR, fs::is_directory_error }, + { ENOSPC, fs::out_of_space_error }, + { ENOMEM, fs::out_of_memory_error }, + { EMFILE, fs::out_of_resource_error } +# endif + }; + + fs::error_code lookup_error( int sys_err_code ) + { + for ( const ec_xlate * cur = &ec_table[0]; + cur != ec_table + + sizeof(ec_table)/sizeof(ec_xlate); ++cur ) + { + if ( sys_err_code == cur->sys_ec ) return cur->ec; + } + return fs::system_error; // general system error code + } + + // These helper functions work for POSIX and Windows. For systems where + // path->native_file_string() != path->native_directory_string(), more + // care would be required to get the right form for the function involved. + + std::string other_error_prep( + const std::string & who, + const std::string & message ) + { + return who + ": " + message; + } + + std::string other_error_prep( + const std::string & who, + const fs::path & path1, + const std::string & message ) + { + return who + ": \"" + path1.native_file_string() + "\": " + message; + } + + std::string system_error_prep( + const std::string & who, + const fs::path & path1, + int sys_err_code ) + { + return who + ": \"" + path1.native_file_string() + "\": " + + system_message( sys_err_code ); + } + + std::string system_error_prep( + const std::string & who, + const fs::path & path1, + const fs::path & path2, + int sys_err_code ) + { + return who + ": \"" + path1.native_file_string() + + "\", \"" + path2.native_file_string() + "\": " + + system_message( sys_err_code ); + } + +} // unnamed namespace + +namespace boost +{ + namespace filesystem + { + +// filesystem_error implementation -----------------------------------------// + + filesystem_error::filesystem_error( + const std::string & who, + const std::string & message ) + : std::runtime_error( + other_error_prep( who, message ).c_str() ), + m_sys_err(0), m_err(other_error), m_who(who) + {} + + filesystem_error::filesystem_error( + const std::string & who, + const path & path1, + const std::string & message ) + : std::runtime_error( + other_error_prep( who, path1, message ).c_str() ), + m_sys_err(0), m_err(other_error), m_who(who), m_path1(path1) + {} + + filesystem_error::filesystem_error( + const std::string & who, + const path & path1, + int sys_err_code ) + : std::runtime_error( + system_error_prep( who, path1, sys_err_code ).c_str() ), + m_sys_err(sys_err_code), m_err(lookup_error(sys_err_code)), + m_who(who), m_path1(path1) + {} + + filesystem_error::filesystem_error( + const std::string & who, + const path & path1, + const path & path2, + int sys_err_code ) + : std::runtime_error( + system_error_prep( who, path1, path2, sys_err_code ).c_str() ), + m_sys_err(sys_err_code), m_err(lookup_error(sys_err_code)), + m_who(who), m_path1(path1), m_path2(path2) + {} + + filesystem_error::~filesystem_error() throw() + { + } + + namespace detail + { + int system_error_code() // artifact of POSIX and WINDOWS error reporting + { + # ifdef BOOST_WINDOWS + return ::GetLastError(); + # else + return errno; // GCC 3.1 won't accept ::errno + # endif + } + } // namespace detail + } // namespace filesystem +} // namespace boost + diff --git a/boost/libs/filesystem/src/operations_posix_windows.cpp b/boost/libs/filesystem/src/operations_posix_windows.cpp new file mode 100644 index 0000000000..33e33af67a --- /dev/null +++ b/boost/libs/filesystem/src/operations_posix_windows.cpp @@ -0,0 +1,484 @@ +// directory_posix_windows.cpp ---------------------------------------------// + +// < ----------------------------------------------------------------------- > +// < Copyright © 2002 Beman Dawes. > +// < Copyright © 2001 Dietmar Kühl, All Rights Reserved > +// < > +// < Permission to use, copy, modify, distribute and sell this > +// < software for any purpose is hereby granted without fee, provided > +// < that the above copyright notice appears in all copies and that > +// < both that copyright notice and this permission notice appear in > +// < supporting documentation. The authors make no representations about > +// < the suitability of this software for any purpose. It is provided > +// < "as is" without expressed or implied warranty. > +// < ----------------------------------------------------------------------- > + +// See http://www.boost.org/libs/filesystem for documentation. + +//----------------------------------------------------------------------------// + + +// The point of this implementation is to prove the interface. There is no +// claim the implementation is efficient, follows good coding practice, etc. + + +//----------------------------------------------------------------------------// + +#include +#include +#include +#include +#include +//#include + +namespace fs = boost::filesystem; + +// BOOST_POSIX or BOOST_WINDOWS specify which API to use. +# if !defined( BOOST_WINDOWS ) && !defined( BOOST_POSIX ) +# if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__) +# define BOOST_WINDOWS +# else +# define BOOST_POSIX +# endif +# endif + +# if defined(BOOST_WINDOWS) +# include "windows.h" + +// For Windows, the xxxA form of various function names is used to avoid +// inadvertently getting wide forms of the functions. (The undecorated +// forms are actually macros, so can misfire if the user has various +// other macros defined. There was a bug report of this happening.) + +# else +# include "sys/stat.h" +# include "dirent.h" +# include "unistd.h" +# include "fcntl.h" +# endif + +#include +#include +#include +#include + +// helpers -----------------------------------------------------------------// + +namespace +{ +#ifdef BOOST_POSIX + +# define BOOST_HANDLE DIR * +# define BOOST_INVALID_HANDLE_VALUE 0 +# define BOOST_SYSTEM_DIRECTORY_TYPE struct dirent * + + inline const char * find_first_file( const char * dir, + BOOST_HANDLE & handle, BOOST_SYSTEM_DIRECTORY_TYPE & ) + // Returns: 0 if error, otherwise name + { + const char * dummy_first_name = "."; + return ( (handle = ::opendir( dir )) + == BOOST_INVALID_HANDLE_VALUE ) ? 0 : dummy_first_name; + } + + inline void find_close( BOOST_HANDLE handle ) + { + assert( handle != BOOST_INVALID_HANDLE_VALUE ); + ::closedir( handle ); + } + + inline const char * find_next_file( + BOOST_HANDLE handle, const fs::path & ph, BOOST_SYSTEM_DIRECTORY_TYPE & ) + // Returns: if EOF 0, otherwise name + // Throws: if system reports error + { + +// TODO: use readdir_r() if available, so code is multi-thread safe. +// Fly-in-ointment: not all platforms support readdir_r(). + + struct dirent * dp; + errno = 0; + if ( (dp = ::readdir( handle )) == 0 ) + { + if ( errno != 0 ) + { + boost::throw_exception( + fs::filesystem_error( + "boost::filesystem::directory_iterator::operator++", + ph, errno ) ); + } + else { return 0; } // end reached + } + return dp->d_name; + } +#else // BOOST_WINDOWS + +# define BOOST_HANDLE HANDLE +# define BOOST_INVALID_HANDLE_VALUE INVALID_HANDLE_VALUE +# define BOOST_SYSTEM_DIRECTORY_TYPE WIN32_FIND_DATAA + + inline const char * find_first_file( const char * dir, + BOOST_HANDLE & handle, BOOST_SYSTEM_DIRECTORY_TYPE & data ) + // Returns: 0 if error, otherwise name + { +// std::cout << "find_first_file " << dir << std::endl; + std::string dirpath( std::string(dir) + "/*" ); + return ( (handle = ::FindFirstFileA( dirpath.c_str(), &data )) + == BOOST_INVALID_HANDLE_VALUE ) ? 0 : data.cFileName; + } + + inline void find_close( BOOST_HANDLE handle ) + { +// std::cout << "find_close" << std::endl; + assert( handle != BOOST_INVALID_HANDLE_VALUE ); + ::FindClose( handle ); + } + + inline const char * find_next_file( + BOOST_HANDLE handle, const fs::path & ph, + BOOST_SYSTEM_DIRECTORY_TYPE & data ) + // Returns: 0 if EOF, otherwise name + // Throws: if system reports error + { + if ( ::FindNextFileA( handle, &data ) == 0 ) + { + if ( ::GetLastError() != ERROR_NO_MORE_FILES ) + { + boost::throw_exception( fs::filesystem_error( + "boost::filesystem::directory_iterator::operator++", + ph.branch_path(), fs::detail::system_error_code() ) ); + } + else { return 0; } // end reached + } + return data.cFileName; + } + +#endif + + fs::directory_iterator end_itr; + + bool is_empty_directory( const fs::path & dir_path ) + { + return fs::directory_iterator(dir_path) == end_itr; + } + + unsigned long remove_all_aux( const fs::path & ph ) + { + unsigned long count = 1; + if ( fs::is_directory( ph ) ) + { + for ( fs::directory_iterator itr( ph ); + itr != end_itr; ++itr ) + { + count += remove_all_aux( *itr ); + } + } + fs::remove( ph ); + return count; + } + +} // unnamed namespace + +namespace boost +{ + namespace filesystem + { + +// dir_itr_imp -------------------------------------------------------------// + + class directory_iterator::dir_itr_imp + { + public: + path entry_path; + BOOST_HANDLE handle; + + ~dir_itr_imp() + { + if ( handle != BOOST_INVALID_HANDLE_VALUE ) find_close( handle ); + } + }; + +// directory_iterator implementation ---------------------------------------// + + // default ctor creates the "end" iterator (by letting base default to 0) + directory_iterator::directory_iterator() {} + + directory_iterator::directory_iterator( const path & dir_path ) + { + m_imp.reset( new dir_itr_imp ); + BOOST_SYSTEM_DIRECTORY_TYPE scratch; + const char * name = 0; // initialization quiets compiler warnings + if ( dir_path.empty() ) + m_imp->handle = BOOST_INVALID_HANDLE_VALUE; + else + name = find_first_file( dir_path.native_directory_string().c_str(), + m_imp->handle, scratch ); // sets handle + + if ( m_imp->handle != BOOST_INVALID_HANDLE_VALUE ) + { + m_imp->entry_path = dir_path; + m_imp->entry_path.m_path_append( name, path::nocheck ); + while ( m_imp.get() + && ( m_imp->entry_path.leaf() == "." + || m_imp->entry_path.leaf() == ".." ) ) + { operator++(); } + } + else + { + boost::throw_exception( filesystem_error( + "boost::filesystem::directory_iterator constructor", + dir_path, fs::detail::system_error_code() ) ); + } + } + + path const & directory_iterator::m_deref() const + { + assert( m_imp.get() ); // fails if dereference end iterator + return m_imp->entry_path; + } + + void directory_iterator::m_inc() + { + assert( m_imp.get() ); // fails on increment end iterator + assert( m_imp->handle != BOOST_INVALID_HANDLE_VALUE ); // reality check + + BOOST_SYSTEM_DIRECTORY_TYPE scratch; + const char * name; + if ( (name = find_next_file( m_imp->handle, + m_imp->entry_path, scratch )) != 0 ) + { + m_imp->entry_path.m_replace_leaf( name ); + } + else + { + m_imp.reset(); // make base() the end iterator + } + } + +// free functions ----------------------------------------------------------// + + bool exists( const path & ph ) + { +# ifdef BOOST_POSIX + struct stat path_stat; + return ::stat( ph.string().c_str(), &path_stat ) == 0; +# else + return ::GetFileAttributesA( ph.string().c_str() ) != 0xFFFFFFFF; +# endif + } + + bool is_directory( const path & ph ) + { +# ifdef BOOST_POSIX + struct stat path_stat; + if ( ::stat( ph.native_directory_string().c_str(), &path_stat ) != 0 ) + boost::throw_exception( filesystem_error( + "boost::filesystem::is_directory", + ph, fs::detail::system_error_code() ) ); + return S_ISDIR( path_stat.st_mode ); +# else + DWORD attributes = ::GetFileAttributesA( ph.native_directory_string().c_str() ); + if ( attributes == 0xFFFFFFFF ) + boost::throw_exception( filesystem_error( + "boost::filesystem::is_directory", + ph, fs::detail::system_error_code() ) ); + return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; +# endif + } + + bool _is_empty( const path & ph ) + { +# ifdef BOOST_POSIX + struct stat path_stat; + if ( ::stat( ph.string().c_str(), &path_stat ) != 0 ) + boost::throw_exception( filesystem_error( + "boost::filesystem::is_empty", + ph, fs::detail::system_error_code() ) ); + + return S_ISDIR( path_stat.st_mode ) + ? is_empty_directory( ph ) + : path_stat.st_size == 0; +# else + WIN32_FILE_ATTRIBUTE_DATA fad; + if ( !::GetFileAttributesExA( ph.string().c_str(), + ::GetFileExInfoStandard, &fad ) ) + boost::throw_exception( filesystem_error( + "boost::filesystem::is_empty", + ph, fs::detail::system_error_code() ) ); + + return ( fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) + ? is_empty_directory( ph ) + :( !fad.nFileSizeHigh && !fad.nFileSizeLow ); +# endif + } + + void create_directory( const path & dir_path ) + { +# ifdef BOOST_POSIX + if ( ::mkdir( dir_path.native_directory_string().c_str(), + S_IRWXU|S_IRWXG|S_IRWXO ) != 0 ) +# else + if ( !::CreateDirectoryA( dir_path.native_directory_string().c_str(), 0 ) ) +# endif + boost::throw_exception( filesystem_error( + "boost::filesystem::create_directory", + dir_path, fs::detail::system_error_code() ) ); + } + + bool remove( const path & ph ) + { + if ( exists( ph ) ) + { +# ifdef BOOST_POSIX + if ( ::remove( ph.string().c_str() ) != 0 ) + { +# else + if ( is_directory( ph ) ) + { + if ( !::RemoveDirectoryA( ph.string().c_str() ) ) + boost::throw_exception( filesystem_error( + "boost::filesystem::remove", + ph, fs::detail::system_error_code() ) ); + } + else + { + if ( !::DeleteFileA( ph.string().c_str() ) ) +# endif + boost::throw_exception( filesystem_error( + "boost::filesystem::remove", + ph, fs::detail::system_error_code() ) ); + } + return true; + } + return false; + } + + unsigned long remove_all( const path & ph ) + { + return exists( ph ) ? remove_all_aux( ph ) : 0; + } + + void rename( const path & old_path, + const path & new_path ) + { +# ifdef BOOST_POSIX + if ( exists( new_path ) // POSIX is too permissive so must check + || ::rename( old_path.string().c_str(), new_path.string().c_str() ) != 0 ) +# else + if ( !::MoveFileA( old_path.string().c_str(), new_path.string().c_str() ) ) +# endif + boost::throw_exception( filesystem_error( + "boost::filesystem::rename", + old_path, new_path, fs::detail::system_error_code() ) ); + } + + void copy_file( const path & from_file_ph, + const path & to_file_ph ) + { +# ifdef BOOST_POSIX + // TODO: Ask POSIX experts if this is the best way to copy a file + + const std::size_t buf_sz = 32768; + boost::scoped_array buf( new char [buf_sz] ); + int infile, outfile=0; // init quiets compiler warning + + if ( (infile = ::open( from_file_ph.string().c_str(), + O_RDONLY )) < 0 + || (outfile = ::open( to_file_ph.string().c_str(), + O_WRONLY | O_CREAT | O_EXCL, + S_IRWXU|S_IRWXG|S_IRWXO )) < 0 ) + { + if ( infile != 0 ) ::close( infile ); + boost::throw_exception( filesystem_error( + "boost::filesystem::copy_file", + from_file_ph, to_file_ph, fs::detail::system_error_code() ) ); + } + + ssize_t sz; + while ( (sz = ::read( infile, buf.get(), buf_sz )) > 0 + && (sz = ::write( outfile, buf.get(), sz )) > 0 ) {} + + ::close( infile ); + ::close( outfile ); + + if ( sz != 0 ) +# else + if ( !::CopyFileA( from_file_ph.string().c_str(), + to_file_ph.string().c_str(), /*fail_if_exists=*/true ) ) +# endif + boost::throw_exception( filesystem_error( + "boost::filesystem::copy_file", + from_file_ph, to_file_ph, fs::detail::system_error_code() ) ); + } + + path current_path() + { +# ifdef BOOST_POSIX + long path_max = ::pathconf( ".", _PC_PATH_MAX ); + if ( path_max < 1 ) + boost::throw_exception( + filesystem_error( "boost::filesystem::current_path", + "_PC_PATH_MAX < 1" ) ); + boost::scoped_array + buf( new char[static_cast(path_max)] ); + if ( ::getcwd( buf.get(), static_cast(path_max) ) == 0 ) +# else + DWORD sz; + if ( (sz = ::GetCurrentDirectoryA( 0, static_cast(0) )) == 0 ) + boost::throw_exception( + filesystem_error( "boost::filesystem::current_path", + "size is 0" ) ); + boost::scoped_array buf( new char[sz] ); + if ( ::GetCurrentDirectoryA( sz, buf.get() ) == 0 ) +# endif + boost::throw_exception( + filesystem_error( "boost::filesystem::current_path", path(), + fs::detail::system_error_code() ) ); + return path( buf.get(), native ); + } + + const path & initial_path() + { + static path init_path; + if ( init_path.empty() ) init_path = current_path(); + return init_path; + } + + path system_complete( const path & ph ) + { +# ifdef BOOST_WINDOWS + if ( ph.empty() ) return ph; + char buf[MAX_PATH]; + char * pfn; + std::size_t len = ::GetFullPathNameA( ph.string().c_str(), + sizeof(buf) , buf, &pfn ); + if ( !len ) + { boost::throw_exception( + filesystem_error( "boost::filesystem::system_complete", + ph, "size is 0" ) ); } + buf[len] = '\0'; + return path( buf, native ); +# else + return (ph.empty() || ph.is_complete()) + ? ph : current_path() / ph; +# endif + } + + path complete( const path & ph, const path & base ) + { + assert( base.is_complete() + && (ph.is_complete() || !ph.has_root_name()) ); // precondition +# ifdef BOOST_WINDOWS + if (ph.empty() || ph.is_complete()) return ph; + if ( !ph.has_root_name() ) + return ph.has_root_directory() + ? path( base.root_name(), native ) / ph + : base / ph; + return base / ph; +# else + return (ph.empty() || ph.is_complete()) ? ph : base / ph; +# endif + } + } // namespace filesystem +} // namespace boost + diff --git a/boost/libs/filesystem/src/path_posix_windows.cpp b/boost/libs/filesystem/src/path_posix_windows.cpp new file mode 100644 index 0000000000..4e6f4e8a17 --- /dev/null +++ b/boost/libs/filesystem/src/path_posix_windows.cpp @@ -0,0 +1,566 @@ +// path implementation -----------------------------------------------------// + +// (C) Copyright Beman Dawes 2002. Permission to copy, +// use, modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided "as is" +// without express or implied warranty, and with no claim as to its +// suitability for any purpose. + +// See http://www.boost.org/libs/filesystem for documentation. + + +//****************************************************************************// + +// WARNING: This code was hacked time and time again as different library +// designs were tried. Thus portions may be residue from the earlier +// experiments, and be totally stupid or wrong in light of the final library +// specifications. The code needs to be reviewed line-by-line to elmininate +// such problems. + +//****************************************************************************// + +// BOOST_POSIX or BOOST_WINDOWS specify which API to use. +# if !defined( BOOST_WINDOWS ) && !defined( BOOST_POSIX ) +# if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__) +# define BOOST_WINDOWS +# else +# define BOOST_POSIX +# endif +# endif + +#include +#include + +namespace fs = boost::filesystem; + +#include +#ifdef BOOST_NO_STDC_NAMESPACE + namespace std { using ::strlen; } +#endif + +#include +#include // SGI MIPSpro compilers need this +#include +#include + +// helpers -----------------------------------------------------------------// + +namespace +{ + // POSIX & Windows cases: "", "/", "/foo", "foo", "foo/bar" + // Windows only cases: "c:", "c:/", "c:foo", "c:/foo", + // "prn:", "//share", "//share/", "//share/foo" + + std::string::size_type leaf_pos( const std::string & str, + std::string::size_type end_pos ) // end_pos is past-the-end position + // return 0 if str itself is leaf (or empty) + { + if ( end_pos && str[end_pos-1] == '/' ) return end_pos-1; + + std::string::size_type pos( str.find_last_of( '/', end_pos-1 ) ); +# ifdef BOOST_WINDOWS + if ( pos == std::string::npos ) pos = str.find_last_of( ':', end_pos-2 ); +# endif + + return ( pos == std::string::npos // path itself must be a leaf (or empty) +# ifdef BOOST_WINDOWS + || (pos == 1 && str[0] == '/') // or share +# endif + ) ? 0 // so leaf is entire string + : pos + 1; // or starts after delimiter + } + + void first_name( const std::string & src, std::string & target ) + { + target = ""; // VC++ 6.0 doesn't have string::clear() + std::string::const_iterator itr( src.begin() ); + +# ifdef BOOST_WINDOWS + // deal with //share + if ( src.size() >= 2 && src[0] == '/' && src[1] == '/' ) + { target = "//"; itr += 2; } +# endif + + while ( itr != src.end() +# ifdef BOOST_WINDOWS + && *itr != ':' +# endif + && *itr != '/' ) { target += *itr++; } + + if ( itr == src.end() ) return; + +# ifdef BOOST_WINDOWS + if ( *itr == ':' ) + { + target += *itr++; + return; + } +# endif + + // *itr is '/' + if ( itr == src.begin() ) { target += '/'; } + return; + } + + const char invalid_chars[] = + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F" + "<>:\"/\\|*?"; + // note that the terminating '\0' is part of the string - thus the size below + // is sizeof(invalid_chars) rather than sizeof(invalid_chars)-1. I + const std::string invalid_generic( invalid_chars, sizeof(invalid_chars) ); + + const std::string valid_posix( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-" ); + + const std::string valid_boost_file( + "abcdefghijklmnopqrstuvwxyz0123456789._-" ); + const std::string valid_boost_directory( + "abcdefghijklmnopqrstuvwxyz0123456789_-" ); + +} // unnamed namespace + +//----------------------------------------------------------------------------// + +namespace boost +{ + namespace filesystem + { + + // error checking functions --------------------------------------------// + + bool generic_name( const std::string & name ) + { + return name.size() != 0 + && name.find_first_of( invalid_generic ) == std::string::npos + && name != "." + && name != ".." + && *name.begin() != ' ' + && *(name.end()-1) != ' '; + } + + bool posix_name( const std::string & name ) + { + return name.find_first_not_of( valid_posix ) == std::string::npos + && name != "."; + } + + const path & check_posix_leaf( const path & ph ) + { + if ( !posix_name( ph.leaf() ) ) + boost::throw_exception( filesystem_error( + "boost::filesystem::check_posix_leaf", + ph, "invalid posix name: \"" + + ph.leaf() + "\"" ) ); + return ph; + } + + bool boost_file_name( const std::string & name ) + { + return name.size() <= 31 + && name.find_first_not_of( valid_boost_file ) == std::string::npos + && name != "."; + } + + bool boost_directory_name( const std::string & name ) + { + return name.size() <= 31 + && name.find_first_not_of( valid_boost_directory ) == std::string::npos; + } + +// path implementation -----------------------------------------------------// + + path::path( const std::string & src ) + { + m_path_append( src ); + } + + path::path( const char * src ) + { + m_path_append( src ); + } + + path::path( const std::string & src, path_format ) + { + m_path_append( src, platform ); + } + + path::path( const char * src, path_format ) + { + m_path_append( src, platform ); + } + + path & path::operator /=( const path & rhs ) + { + m_path_append( rhs.m_path, nocheck ); + return *this; + } + + void path::m_path_append( const std::string & src, source_context context ) + { + // convert backslash to forward slash if context is "platform" + // check names if context is "generic" + // allow system-specific-root if context is not "generic" + + assert( src.size() == std::strlen( src.c_str() ) ); // no embedded 0 + + if ( src.size() == 0 ) return; + + std::string::const_iterator itr( src.begin() ); + + // [root-filesystem] +# ifdef BOOST_WINDOWS + if ( context != generic && src.size() >= 2 ) + { + // drive or device + if ( src[1] == ':' || src[src.size()-1] == ':' ) + { + for ( ; *itr != ':'; ++itr ) m_path += *itr; + m_path += ':'; + ++itr; + } + + // share + else if ( (*itr == '/' || (*itr == '\\' && context == platform)) + && (*(itr+1) == '/' || (*(itr+1) == '\\' && context == platform)) ) + { + m_path += "//"; + for ( itr += 2; + itr != src.end() && *itr != '/' && *itr != '\\'; + ++itr ) m_path += *itr; + } + } +# endif + + // root directory [ "/" ] + if ( itr != src.end() && (*itr == '/' +# ifdef BOOST_WINDOWS + || (*itr == '\\' && context == platform) +# endif + ) ) + { + ++itr; + if ( m_path.size() == 0 +# ifdef BOOST_WINDOWS + || m_path[m_path.size()-1] == ':' // drive or device + || ( // share + m_path.size() > 2 + && m_path[0] == '/' + && m_path[1] == '/' + && m_path.find( '/', 2 ) == std::string::npos + ) +# endif + ) m_path += '/'; + } + + // element { "/" element } [ "/" ] + while ( itr != src.end() ) + { + + // append '/' if needed + if ( !empty() + && *(m_path.end()-1) != ':' && *(m_path.end()-1) != '/' ) + m_path += '/'; + + if ( *itr == '.'&& (itr+1) != src.end() && *(itr+1) == '.' ) // ".." + { + if ( m_path.size() >= 2 // there is a named parent directory present + && *(m_path.end()-1) == '/' +# ifdef BOOST_WINDOWS + && *(m_path.end()-2) != ':' +# endif + && *(m_path.end()-2) != '.' ) + { + // reference to parent so erase child + std::string::iterator child( m_path.end()-2 ); + + while ( child != m_path.begin() && *child != '/' +# ifdef BOOST_WINDOWS + && *child != ':' +# endif + ) --child; + + // only erase '/' if it is a separator rather than part of the root + if ( (*child == '/' + && (child == m_path.begin() +# ifdef BOOST_WINDOWS + || *(child-1) == ':')) + || *child == ':' +# else + )) +# endif + ) ++child; + + m_path.erase( child, m_path.end() ); + } + else { m_path += ".."; } + ++itr; + ++itr; + } // ".." + else // element is name + { + std::string name; + do + { name += *itr; } + while ( ++itr != src.end() && *itr != '/' +# ifdef BOOST_WINDOWS + && (*itr != '\\' || context != platform) +# endif + ); + + if ( context == generic && !generic_name( name ) ) + { + boost::throw_exception( filesystem_error( + "boost::filesystem::path", + "invalid name \"" + name + "\" in path: \"" + src + "\"" ) ); + } + + m_path += name; + } + + if ( itr != src.end() ) + { + if ( *itr == '/' +# ifdef BOOST_WINDOWS + || (*itr == '\\' && context == platform) +# endif + ) ++itr; + else + boost::throw_exception( filesystem_error( + "boost::filesystem::path", + "invalid path syntax: \"" + src + "\"" ) ); + } + + } // while more elements + } + +// path conversion functions ------------------------------------------------// + + std::string path::native_file_string() const + { +# ifdef BOOST_WINDOWS + std::string s( m_path ); + for ( std::string::iterator itr( s.begin() ); + itr != s.end(); ++itr ) + if ( *itr == '/' ) *itr = '\\'; + return s; +# else + return m_path; +# endif + } + + std::string path::native_directory_string() const + { return native_file_string(); } + +// path decomposition functions ---------------------------------------------// + + path::iterator path::begin() const + { + iterator itr; + itr.base().path_ptr = this; + first_name( m_path, itr.base().name ); + itr.base().pos = 0; + return itr; + } + + void path::m_replace_leaf( const char * new_leaf ) + { + m_path.erase( leaf_pos( m_path, m_path.size() ) ); + m_path += new_leaf; + } + + std::string path::leaf() const + { + return m_path.substr( leaf_pos( m_path, m_path.size() ) ); + } + + namespace detail + { + inline bool is_absolute_root( const std::string & s, + std::string::size_type len ) + { + return + len && s[len-1] == '/' + && + ( + len == 1 // "/" +# ifdef BOOST_WINDOWS + || ( len > 1 + && ( s[len-2] == ':' // drive or device + || ( s[0] == '/' // share + && s[1] == '/' + && s.find( '/', 2 ) == len-1 + ) + ) + ) +# endif + ); + } + } + + path path::branch_path() const + { + std::string::size_type end_pos( leaf_pos( m_path, m_path.size() ) ); + + // skip a '/' unless it is a root directory + if ( end_pos && m_path[end_pos-1] == '/' + && !detail::is_absolute_root( m_path, end_pos ) ) --end_pos; + return path( m_path.substr( 0, end_pos ), native ); + } + + path path::relative_path() const + { + std::string::size_type pos( 0 ); + if ( m_path.size() && m_path[0] == '/' ) + { pos = 1; +# ifdef BOOST_WINDOWS + if ( m_path.size()>1 && m_path[1] == '/' ) // share + { + if ( (pos = m_path.find( '/', 2 )) != std::string::npos ) ++pos; + else return path(); + } + } + else if ( (pos = m_path.find( ':' )) == std::string::npos ) pos = 0; + else // has ':' + { + if ( ++pos < m_path.size() && m_path[pos] == '/' ) ++pos; +# endif + } + return path( m_path.substr( pos ) ); + } + + std::string path::root_name() const + { +# ifdef BOOST_WINDOWS + std::string::size_type pos( m_path.find( ':' ) ); + if ( pos != std::string::npos ) return m_path.substr( 0, pos+1 ); + if ( m_path.size() > 2 && m_path[0] == '/' && m_path[1] == '/' ) + { + pos = m_path.find( '/', 2 ); + return m_path.substr( 0, pos ); + } +# endif + return std::string(); + } + + std::string path::root_directory() const + { + return std::string( + ( m_path.size() && m_path[0] == '/' ) // covers both "/" and "//share" +# ifdef BOOST_WINDOWS + || ( m_path.size() > 2 + && m_path[1] == ':' + && m_path[2] == '/' ) // "c:/" +# endif + ? "/" : "" ); + } + + path path::root_path() const + { + return path( +# ifdef BOOST_WINDOWS + root_name(), native ) /= root_directory(); +# else + root_directory() ); +# endif + } + +// path query functions -----------------------------------------------------// + + bool path::is_complete() const + { +# ifdef BOOST_WINDOWS + return m_path.size() > 2 + && ( (m_path[1] == ':' && m_path[2] == '/') // "c:/" + || (m_path[0] == '/' && m_path[1] == '/') // "//share" + || m_path[m_path.size()-1] == ':' ); +# else + return m_path.size() && m_path[0] == '/'; +# endif + } + + bool path::has_root_path() const + { + return ( m_path.size() + && m_path[0] == '/' ) // covers both "/" and "//share" +# ifdef BOOST_WINDOWS + || ( m_path.size() > 1 && m_path[1] == ':' ) // "c:" and "c:/" + || ( m_path.size() > 3 + && m_path[m_path.size()-1] == ':' ) // "device:" +# endif + ; + } + + bool path::has_root_name() const + { +# ifdef BOOST_WINDOWS + return m_path.size() > 1 + && ( m_path[1] == ':' // "c:" + || m_path[m_path.size()-1] == ':' // "prn:" + || (m_path[0] == '/' && m_path[1] == '/') // "//share" + ); +# else + return false; +# endif + } + + bool path::has_root_directory() const + { + return ( m_path.size() + && m_path[0] == '/' ) // covers both "/" and "//share" +# ifdef BOOST_WINDOWS + || ( m_path.size() > 2 + && m_path[1] == ':' && m_path[2] == '/' ) // "c:/" +# endif + ; + } + + bool path::has_relative_path() const { return !relative_path().empty(); } + bool path::has_branch_path() const { return !branch_path().empty(); } + + +// path_itr_imp implementation ----------------------------------------------// + + namespace detail + { + void path_itr_imp::operator++() + { + assert( pos < path_ptr->m_path.size() ); // detect increment past end + pos += name.size(); + if ( pos == path_ptr->m_path.size() ) + { + name = ""; // not strictly required, but might aid debugging + return; + } + if ( path_ptr->m_path[pos] == '/' ) + { +# ifdef BOOST_WINDOWS + if ( name[name.size()-1] == ':' // drive or device + || (name[0] == '/' && name[1] == '/') ) // share + { + name = "/"; + return; + } +# endif + ++pos; + } + std::string::size_type end_pos( path_ptr->m_path.find( '/', pos ) ); + if ( end_pos == std::string::npos ) end_pos = path_ptr->m_path.size(); + name = path_ptr->m_path.substr( pos, end_pos - pos ); + } + + void path_itr_imp::operator--() + { + assert( pos ); // detect decrement of begin + std::string::size_type end_pos( pos ); + + // skip a '/' unless it is a root directory + if ( path_ptr->m_path[end_pos-1] == '/' + && !detail::is_absolute_root( path_ptr->m_path, end_pos ) ) --end_pos; + pos = leaf_pos( path_ptr->m_path, end_pos ); + name = path_ptr->m_path.substr( pos, end_pos - pos ); + } + + } // namespace detail + } // namespace filesystem +} // namespace boost diff --git a/configure.ac b/configure.ac index 25c22a1dd5..9aa611350e 100644 --- a/configure.ac +++ b/configure.ac @@ -389,6 +389,8 @@ AC_CONFIG_SUBDIRS(lib lib/reLyX) AC_CONFIG_FILES([Makefile \ boost/Makefile \ boost/libs/Makefile \ + boost/libs/filesystem/Makefile \ + boost/libs/filesystem/src/Makefile \ boost/libs/regex/Makefile \ boost/libs/regex/src/Makefile \ boost/libs/signals/Makefile \ -- 2.39.2