/*============================================================================= | |
Boost.Wave: A Standard compliant C++ preprocessor library | |
http://www.boost.org/ | |
Copyright (c) 2001-2011 Hartmut Kaiser. 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) | |
=============================================================================*/ | |
#if !defined(CPP_INCLUDE_PATHS_HPP_AF620DA4_B3D2_4221_AD91_8A1ABFFB6944_INCLUDED) | |
#define CPP_INCLUDE_PATHS_HPP_AF620DA4_B3D2_4221_AD91_8A1ABFFB6944_INCLUDED | |
#include <string> | |
#include <list> | |
#include <utility> | |
#include <boost/wave/wave_config.hpp> | |
#include <boost/wave/util/filesystem_compatibility.hpp> | |
#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 | |
#include <boost/multi_index_container.hpp> | |
#include <boost/multi_index/member.hpp> | |
#include <boost/multi_index/ordered_index.hpp> | |
#endif | |
#if BOOST_WAVE_SERIALIZATION != 0 | |
#include <boost/serialization/serialization.hpp> | |
#include <boost/serialization/utility.hpp> | |
#include <boost/serialization/collections_save_imp.hpp> | |
#include <boost/serialization/collections_load_imp.hpp> | |
#include <boost/serialization/split_free.hpp> | |
#endif | |
#include <boost/filesystem/path.hpp> | |
#include <boost/filesystem/operations.hpp> | |
// this must occur after all of the includes and before any code appears | |
#ifdef BOOST_HAS_ABI_HEADERS | |
#include BOOST_ABI_PREFIX | |
#endif | |
/////////////////////////////////////////////////////////////////////////////// | |
namespace boost { namespace wave { namespace util { | |
#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 | |
/////////////////////////////////////////////////////////////////////////////// | |
// Tags for accessing both sides of a bidirectional map | |
struct from {}; | |
struct to {}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// The class template bidirectional_map wraps the specification | |
// of a bidirectional map based on multi_index_container. | |
template<typename FromType, typename ToType> | |
struct bidirectional_map | |
{ | |
typedef std::pair<FromType, ToType> value_type; | |
#if defined(BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS) || \ | |
(defined(BOOST_MSVC) && \ | |
( (BOOST_MSVC < 1300) || (BOOST_MSVC == 1600) )) || \ | |
(defined(BOOST_INTEL_CXX_VERSION) && \ | |
(defined(_MSC_VER) && (BOOST_INTEL_CXX_VERSION <= 700))) | |
BOOST_STATIC_CONSTANT(unsigned, from_offset = offsetof(value_type, first)); | |
BOOST_STATIC_CONSTANT(unsigned, to_offset = offsetof(value_type, second)); | |
typedef boost::multi_index::multi_index_container< | |
value_type, | |
boost::multi_index::indexed_by< | |
boost::multi_index::ordered_unique< | |
boost::multi_index::tag<from>, | |
boost::multi_index::member_offset<value_type, FromType, from_offset> | |
>, | |
boost::multi_index::ordered_non_unique< | |
boost::multi_index::tag<to>, | |
boost::multi_index::member_offset<value_type, ToType, to_offset> | |
> | |
> | |
> type; | |
#else | |
typedef boost::multi_index::multi_index_container< | |
value_type, | |
boost::multi_index::indexed_by< | |
boost::multi_index::ordered_unique< | |
boost::multi_index::tag<from>, | |
boost::multi_index::member<value_type, FromType, &value_type::first> | |
>, | |
boost::multi_index::ordered_non_unique< | |
boost::multi_index::tag<to>, | |
boost::multi_index::member<value_type, ToType, &value_type::second> | |
> | |
> | |
> type; | |
#endif | |
}; | |
#endif // BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 | |
#if BOOST_WAVE_SERIALIZATION != 0 | |
struct load_filepos | |
{ | |
static unsigned int get_line() { return 0; } | |
static unsigned int get_column() { return 0; } | |
static std::string get_file() { return "<loading-state>"; } | |
}; | |
#endif | |
/////////////////////////////////////////////////////////////////////////////// | |
// | |
// include_paths - controlling the include path search order | |
// | |
// General notes: | |
// | |
// Any directories specified with the 'add_include_path()' function before | |
// the function 'set_sys_include_delimiter()' is called are searched only | |
// for the case of '#include "file"' directives, they are not searched for | |
// '#include <file>' directives. If additional directories are specified | |
// with the 'add_include_path()' function after a call to the function | |
// 'set_sys_include_delimiter()', these directories are searched for all | |
// '#include' directives. | |
// | |
// In addition, a call to the function 'set_sys_include_delimiter()' | |
// inhibits the use of the current directory as the first search directory | |
// for '#include "file"' directives. Therefore, the current directory is | |
// searched only if it is requested explicitly with a call to the function | |
// 'add_include_path(".")'. | |
// | |
// Calling both functions, the 'set_sys_include_delimiter()' and | |
// 'add_include_path(".")' allows you to control precisely which | |
// directories are searched before the current one and which are searched | |
// after. | |
// | |
/////////////////////////////////////////////////////////////////////////////// | |
class include_paths | |
{ | |
private: | |
typedef std::list<std::pair<boost::filesystem::path, std::string> > | |
include_list_type; | |
typedef include_list_type::value_type include_value_type; | |
#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 | |
typedef bidirectional_map<std::string, std::string>::type | |
pragma_once_set_type; | |
#endif | |
public: | |
include_paths() | |
: was_sys_include_path(false), | |
current_dir(initial_path()), | |
current_rel_dir(initial_path()) | |
{} | |
bool add_include_path(char const *path_, bool is_system = false) | |
{ | |
return add_include_path(path_, (is_system || was_sys_include_path) ? | |
system_include_paths : user_include_paths); | |
} | |
void set_sys_include_delimiter() { was_sys_include_path = true; } | |
bool find_include_file (std::string &s, std::string &dir, bool is_system, | |
char const *current_file) const; | |
void set_current_directory(char const *path_); | |
boost::filesystem::path get_current_directory() const | |
{ return current_dir; } | |
protected: | |
bool find_include_file (std::string &s, std::string &dir, | |
include_list_type const &pathes, char const *) const; | |
bool add_include_path(char const *path_, include_list_type &pathes_); | |
private: | |
include_list_type user_include_paths; | |
include_list_type system_include_paths; | |
bool was_sys_include_path; // saw a set_sys_include_delimiter() | |
boost::filesystem::path current_dir; | |
boost::filesystem::path current_rel_dir; | |
#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 | |
public: | |
bool has_pragma_once(std::string const &filename) | |
{ | |
using namespace boost::multi_index; | |
return get<from>(pragma_once_files).find(filename) != pragma_once_files.end(); | |
} | |
bool add_pragma_once_header(std::string const &filename, | |
std::string const& guard_name) | |
{ | |
typedef pragma_once_set_type::value_type value_type; | |
return pragma_once_files.insert(value_type(filename, guard_name)).second; | |
} | |
bool remove_pragma_once_header(std::string const& guard_name) | |
{ | |
typedef pragma_once_set_type::index_iterator<to>::type to_iterator; | |
typedef std::pair<to_iterator, to_iterator> range_type; | |
range_type r = pragma_once_files.get<to>().equal_range(guard_name); | |
if (r.first != r.second) { | |
using namespace boost::multi_index; | |
get<to>(pragma_once_files).erase(r.first, r.second); | |
return true; | |
} | |
return false; | |
} | |
private: | |
pragma_once_set_type pragma_once_files; | |
#endif | |
#if BOOST_WAVE_SERIALIZATION != 0 | |
public: | |
BOOST_STATIC_CONSTANT(unsigned int, version = 0x10); | |
BOOST_STATIC_CONSTANT(unsigned int, version_mask = 0x0f); | |
private: | |
friend class boost::serialization::access; | |
template<typename Archive> | |
void save(Archive & ar, const unsigned int version) const | |
{ | |
using namespace boost::serialization; | |
#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 | |
ar & make_nvp("pragma_once_files", pragma_once_files); | |
#endif | |
ar & make_nvp("user_include_paths", user_include_paths); | |
ar & make_nvp("system_include_paths", system_include_paths); | |
ar & make_nvp("was_sys_include_path", was_sys_include_path); | |
} | |
template<typename Archive> | |
void load(Archive & ar, const unsigned int loaded_version) | |
{ | |
using namespace boost::serialization; | |
if (version != (loaded_version & ~version_mask)) { | |
BOOST_WAVE_THROW(preprocess_exception, incompatible_config, | |
"cpp_include_path state version", load_filepos()); | |
return; | |
} | |
#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0 | |
ar & make_nvp("pragma_once_files", pragma_once_files); | |
#endif | |
// verify that the old include paths match the current ones | |
include_list_type user_paths, system_paths; | |
ar & make_nvp("user_include_paths", user_paths); | |
ar & make_nvp("system_include_paths", system_paths); | |
if (user_paths != user_include_paths) | |
{ | |
BOOST_WAVE_THROW(preprocess_exception, incompatible_config, | |
"user include paths", load_filepos()); | |
return; | |
} | |
if (system_paths != system_include_paths) | |
{ | |
BOOST_WAVE_THROW(preprocess_exception, incompatible_config, | |
"system include paths", load_filepos()); | |
return; | |
} | |
ar & make_nvp("was_sys_include_path", was_sys_include_path); | |
} | |
BOOST_SERIALIZATION_SPLIT_MEMBER() | |
#endif | |
}; | |
/////////////////////////////////////////////////////////////////////////////// | |
// Add an include path to one of the search lists (user include path or system | |
// include path). | |
inline | |
bool include_paths::add_include_path ( | |
char const *path_, include_list_type &pathes_) | |
{ | |
namespace fs = boost::filesystem; | |
if (path_) { | |
fs::path newpath = util::complete_path(create_path(path_), current_dir); | |
if (!fs::exists(newpath) || !fs::is_directory(newpath)) { | |
// the given path does not form a name of a valid file system directory | |
// item | |
return false; | |
} | |
pathes_.push_back (include_value_type(newpath, path_)); | |
return true; | |
} | |
return false; | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
// Find an include file by traversing the list of include directories | |
inline | |
bool include_paths::find_include_file (std::string &s, std::string &dir, | |
include_list_type const &pathes, char const *current_file) const | |
{ | |
namespace fs = boost::filesystem; | |
typedef include_list_type::const_iterator const_include_list_iter_t; | |
const_include_list_iter_t it = pathes.begin(); | |
const_include_list_iter_t include_paths_end = pathes.end(); | |
#if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0 | |
if (0 != current_file) { | |
// re-locate the directory of the current file (#include_next handling) | |
// #include_next does not distinguish between <file> and "file" | |
// inclusion, nor does it check that the file you specify has the same | |
// name as the current file. It simply looks for the file named, starting | |
// with the directory in the search path after the one where the current | |
// file was found. | |
fs::path file_path (create_path(current_file)); | |
for (/**/; it != include_paths_end; ++it) { | |
fs::path currpath (create_path((*it).first.string())); | |
if (std::equal(currpath.begin(), currpath.end(), file_path.begin())) | |
{ | |
++it; // start searching with the next directory | |
break; | |
} | |
} | |
} | |
#endif | |
for (/**/; it != include_paths_end; ++it) { | |
fs::path currpath (create_path(s)); | |
if (!currpath.has_root_directory()) { | |
currpath = create_path((*it).first.string()); | |
currpath /= create_path(s); // append filename | |
} | |
if (fs::exists(currpath)) { | |
fs::path dirpath (create_path(s)); | |
if (!dirpath.has_root_directory()) { | |
dirpath = create_path((*it).second); | |
dirpath /= create_path(s); | |
} | |
dir = dirpath.string(); | |
s = normalize(currpath).string(); // found the required file | |
return true; | |
} | |
} | |
return false; | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
// Find an include file by searching the user and system includes in the | |
// correct sequence (as it was configured by the user of the driver program) | |
inline bool | |
include_paths::find_include_file (std::string &s, std::string &dir, | |
bool is_system, char const *current_file) const | |
{ | |
namespace fs = boost::filesystem; | |
// if not system include (<...>), then search current directory first | |
if (!is_system) { | |
if (!was_sys_include_path) { // set_sys_include_delimiter() not called | |
// first have a look at the current directory | |
fs::path currpath (create_path(s)); | |
if (!currpath.has_root_directory()) { | |
currpath = create_path(current_dir.string()); | |
currpath /= create_path(s); | |
} | |
if (fs::exists(currpath) && 0 == current_file) { | |
// if 0 != current_path (#include_next handling) it can't be | |
// the file in the current directory | |
fs::path dirpath (create_path(s)); | |
if (!dirpath.has_root_directory()) { | |
dirpath = create_path(current_rel_dir.string()); | |
dirpath /= create_path(s); | |
} | |
dir = dirpath.string(); | |
s = normalize(currpath).string(); // found in local directory | |
return true; | |
} | |
// iterate all user include file directories to find the file | |
if (find_include_file(s, dir, user_include_paths, current_file)) | |
return true; | |
// ... fall through | |
} | |
else { | |
// if set_sys_include_delimiter() was called, then user include files | |
// are searched in the user search path only | |
return find_include_file(s, dir, user_include_paths, current_file); | |
} | |
// if nothing found, fall through | |
// ... | |
} | |
// iterate all system include file directories to find the file | |
return find_include_file (s, dir, system_include_paths, current_file); | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
// Set current directory from a given file name | |
inline bool | |
as_relative_to(boost::filesystem::path const& path, | |
boost::filesystem::path const& base, boost::filesystem::path& result) | |
{ | |
if (path.has_root_path()) { | |
if (path.root_path() == base.root_path()) | |
return as_relative_to(path.relative_path(), base.relative_path(), result); | |
result = path; // that's our result | |
} | |
else { | |
if (base.has_root_path()) { | |
// cannot find relative path from a relative path and a rooted base | |
return false; | |
} | |
else { | |
typedef boost::filesystem::path::const_iterator path_iterator; | |
path_iterator path_it = path.begin(); | |
path_iterator base_it = base.begin(); | |
while (path_it != path.end() && base_it != base.end() ) { | |
if (*path_it != *base_it) | |
break; | |
++path_it; ++base_it; | |
} | |
for (/**/; base_it != base.end(); ++base_it) | |
result /= ".."; | |
for (/**/; path_it != path.end(); ++path_it) | |
result /= *path_it; | |
} | |
} | |
return true; | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
inline | |
void include_paths::set_current_directory(char const *path_) | |
{ | |
namespace fs = boost::filesystem; | |
fs::path filepath (create_path(path_)); | |
fs::path filename = util::complete_path(filepath, current_dir); | |
if (fs::exists(filename) && fs::is_directory(filename)) { | |
current_rel_dir.clear(); | |
if (!as_relative_to(filepath, current_dir, current_rel_dir)) | |
current_rel_dir = filepath; | |
current_dir = filename; | |
} | |
else { | |
current_rel_dir.clear(); | |
if (!as_relative_to(branch_path(filepath), current_dir, current_rel_dir)) | |
current_rel_dir = branch_path(filepath); | |
current_dir = branch_path(filename); | |
} | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
}}} // namespace boost::wave::util | |
#if BOOST_WAVE_SERIALIZATION != 0 | |
/////////////////////////////////////////////////////////////////////////////// | |
namespace boost { namespace serialization { | |
/////////////////////////////////////////////////////////////////////////////// | |
// Serialization support for boost::filesystem::path | |
template<class Archive> | |
inline void save (Archive & ar, boost::filesystem::path const& p, | |
const unsigned int /* file_version */) | |
{ | |
using namespace boost::serialization; | |
std::string path_str(p.native_file_string()); | |
ar & make_nvp("filepath", path_str); | |
} | |
template<class Archive> | |
inline void load (Archive & ar, boost::filesystem::path &p, | |
const unsigned int /* file_version */) | |
{ | |
using namespace boost::serialization; | |
std::string path_str; | |
ar & make_nvp("filepath", path_str); | |
p = wave::util::create_path(path_str); | |
} | |
// split non-intrusive serialization function member into separate | |
// non intrusive save/load member functions | |
template<class Archive> | |
inline void serialize (Archive & ar, boost::filesystem::path &p, | |
const unsigned int file_version) | |
{ | |
boost::serialization::split_free(ar, p, file_version); | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
// Serialization support for the used multi_index | |
template<class Archive> | |
inline void save (Archive & ar, | |
const typename boost::wave::util::bidirectional_map< | |
std::string, std::string | |
>::type &t, | |
const unsigned int /* file_version */) | |
{ | |
boost::serialization::stl::save_collection< | |
Archive, | |
typename boost::wave::util::bidirectional_map< | |
std::string, std::string | |
>::type | |
>(ar, t); | |
} | |
template<class Archive> | |
inline void load (Archive & ar, | |
typename boost::wave::util::bidirectional_map<std::string, std::string>::type &t, | |
const unsigned int /* file_version */) | |
{ | |
typedef typename boost::wave::util::bidirectional_map< | |
std::string, std::string | |
>::type map_type; | |
boost::serialization::stl::load_collection< | |
Archive, map_type, | |
boost::serialization::stl::archive_input_unique<Archive, map_type>, | |
boost::serialization::stl::no_reserve_imp<map_type> | |
>(ar, t); | |
} | |
// split non-intrusive serialization function member into separate | |
// non intrusive save/load member functions | |
template<class Archive> | |
inline void serialize (Archive & ar, | |
typename boost::wave::util::bidirectional_map< | |
std::string, std::string | |
>::type &t, | |
const unsigned int file_version) | |
{ | |
boost::serialization::split_free(ar, t, file_version); | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
}} // namespace boost::serialization | |
BOOST_CLASS_VERSION(boost::wave::util::include_paths, | |
boost::wave::util::include_paths::version); | |
#endif // BOOST_WAVE_SERIALIZATION != 0 | |
// the suffix header occurs after all of the code | |
#ifdef BOOST_HAS_ABI_HEADERS | |
#include BOOST_ABI_SUFFIX | |
#endif | |
#endif // !defined(CPP_INCLUDE_PATHS_HPP_AF620DA4_B3D2_4221_AD91_8A1ABFFB6944_INCLUDED) |