diff --git a/property_tree/detail/info_parser_default_path_resolver.hpp b/property_tree/detail/info_parser_default_path_resolver.hpp new file mode 100644 index 0000000..9d3cde4 --- /dev/null +++ b/property_tree/detail/info_parser_default_path_resolver.hpp @@ -0,0 +1,27 @@ +#ifndef BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_DEFAULT_PATH_RESOLVER_HPP_INCLUDED +#define BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_DEFAULT_PATH_RESOLVER_HPP_INCLUDED + +namespace boost { namespace property_tree { namespace info_parser +{ + /*! + * \brief Path resolver class implementation + * + * This implementation will not resolve + * paths: it will simply return + * path argument. It was created + * for compatibility purposes. + */ + class default_path_resolver + { + public: + inline const std::string &resolve(const std::string &path) + { + return path; + } + inline void enter(const std::string &) {} + inline void enter() {} + inline void exit() {} + }; +} } } + +#endif diff --git a/property_tree/detail/info_parser_read.hpp b/property_tree/detail/info_parser_read.hpp index b87c2cb..e07daba 100644 --- a/property_tree/detail/info_parser_read.hpp +++ b/property_tree/detail/info_parser_read.hpp @@ -175,10 +175,11 @@ namespace boost { namespace property_tree { namespace info_parser } // Build ptree from info stream - template + template void read_info_internal(std::basic_istream &stream, Ptree &pt, const std::string &filename, + PathResolver &path_resolver, int include_depth) { typedef std::basic_string str_t; @@ -227,13 +228,17 @@ namespace boost { namespace property_tree { namespace info_parser str_t s = read_string(text, NULL); std::string inc_name = convert_chtype(s.c_str()); - std::basic_ifstream inc_stream(inc_name.c_str()); + std::basic_ifstream inc_stream( + path_resolver.resolve(inc_name.c_str())); if (!inc_stream.good()) BOOST_PROPERTY_TREE_THROW(info_parser_error( "cannot open include file " + inc_name, filename, line_no)); + path_resolver.enter(inc_name); read_info_internal(inc_stream, *stack.top(), - inc_name, include_depth + 1); + inc_name, path_resolver, + include_depth + 1); + path_resolver.exit(); } else { // Unknown directive BOOST_PROPERTY_TREE_THROW(info_parser_error( "unknown directive", filename, line_no)); diff --git a/property_tree/detail/info_parser_relative_path_resolver.hpp b/property_tree/detail/info_parser_relative_path_resolver.hpp new file mode 100644 index 0000000..d4f3f7f --- /dev/null +++ b/property_tree/detail/info_parser_relative_path_resolver.hpp @@ -0,0 +1,65 @@ +#ifndef BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_RELATIVE_PATH_RESOLVER_HPP_INCLUDED +#define BOOST_PROPERTY_TREE_DETAIL_INFO_PARSER_RELATIVE_PATH_RESOLVER_HPP_INCLUDED + +#include + +#include + +#include +#include + +namespace boost { namespace property_tree { namespace info_parser +{ + /*! + * \brief Path resolver class implementation + * that resolves paths relatively + * + * This implementation will resolve paths + * relative to base path (directory path of the file contains '#include' directive) + * + * \note The drawback of this implementation + * is dependency on boost::filesystem library + * + */ + class relative_path_resolver + { + std::stack stack; + inline boost::filesystem::path resolve_(const boost::filesystem::path &path) + { + if (path.is_absolute()) + return path; + else + { + if (stack.empty()) + return boost::filesystem::absolute(boost::filesystem::current_path()/path); + else + return boost::filesystem::absolute(stack.top()/path); + } + } + public: + inline std::string resolve(const boost::filesystem::path &path) + { + return resolve(path).string(); + } + inline void enter(const boost::filesystem::path &path) + { + stack.push(resolve_(path).parent_path()); + } + inline void enter() + { + if (stack.empty()) + stack.push(boost::filesystem::current_path()); + else + // this case is unreachable + // probably should not be used + // TODO: should we use BOOST_ASSERT here? + stack.push(stack.top()); + } + inline void exit() + { + stack.pop(); + } + }; +} } } + +#endif diff --git a/property_tree/info_parser.hpp b/property_tree/info_parser.hpp index 683ddad..764ef8a 100644 --- a/property_tree/info_parser.hpp +++ b/property_tree/info_parser.hpp @@ -15,6 +15,7 @@ #include #include #include +#include #include namespace boost { namespace property_tree { namespace info_parser @@ -29,8 +30,18 @@ namespace boost { namespace property_tree { namespace info_parser template void read_info(std::basic_istream &stream, Ptree &pt) { + default_path_resolver path_resolver; + read_info(stream, pt, path_resolver); + } + + template + void read_info(std::basic_istream &stream, Ptree &pt, + PathResolver &path_resolver) + { Ptree local; - read_info_internal(stream, local, std::string(), 0); + path_resolver.enter(); + read_info_internal(stream, local, std::string(), path_resolver, 0); + path_resolver.exit(); pt.swap(local); } @@ -43,8 +54,18 @@ namespace boost { namespace property_tree { namespace info_parser void read_info(std::basic_istream &stream, Ptree &pt, const Ptree &default_ptree) { + default_path_resolver path_resolver; + read_info(stream, pt, default_ptree, path_resolver); + } + + template + void read_info(std::basic_istream &stream, Ptree &pt, + const Ptree &default_ptree, PathResolver &path_resolver) + { try { - read_info(stream, pt); + path_resolver.enter(); + read_info(stream, pt, path_resolver); + path_resolver.exit(); } catch(file_parser_error &) { pt = default_ptree; } @@ -62,6 +83,15 @@ namespace boost { namespace property_tree { namespace info_parser void read_info(const std::string &filename, Ptree &pt, const std::locale &loc = std::locale()) { + default_path_resolver path_resolver; + read_info(filename, pt, path_resolver, loc); + } + + template + void read_info(const std::string &filename, Ptree &pt, + PathResolver &path_resolver, + const std::locale &loc = std::locale()) + { std::basic_ifstream stream(filename.c_str()); if (!stream) { @@ -70,7 +100,9 @@ namespace boost { namespace property_tree { namespace info_parser } stream.imbue(loc); Ptree local; - read_info_internal(stream, local, filename, 0); + path_resolver.enter(filename); + read_info_internal(stream, local, filename, path_resolver, 0); + path_resolver.exit(); pt.swap(local); } @@ -81,14 +113,25 @@ namespace boost { namespace property_tree { namespace info_parser * @note Replaces the existing contents. Strong exception guarantee. * @param default_ptree If parsing fails, pt is set to a copy of this tree. */ - template + template + void read_info(const std::string &filename, + Ptree &pt, + const Ptree &default_ptree, + const std::locale &loc = std::locale()) + { + default_path_resolver path_resolver; + read_info(filename, pt, default_ptree, loc, path_resolver); + } + + template void read_info(const std::string &filename, Ptree &pt, const Ptree &default_ptree, + PathResolver &path_resolver, const std::locale &loc = std::locale()) { try { - read_info(filename, pt, loc); + read_info(filename, pt, path_resolver, loc); } catch(file_parser_error &) { pt = default_ptree; }