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