diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy index 8c81efcd623..a3a22182dca 100644 --- a/lib/config/config_parser.yy +++ b/lib/config/config_parser.yy @@ -443,39 +443,30 @@ lterm: T_LIBRARY rterm { $$ = new SetExpression($1, $2, $3, @$); } - | T_INCLUDE T_STRING + | T_INCLUDE rterm { - $$ = context->HandleInclude(*$2, false, @$); - delete $2; + $$ = new IncludeExpression(Utility::DirName(context->GetPath()), $2, NULL, NULL, IncludeRegular, false, context->GetZone(), context->GetPackage(), @$); } | T_INCLUDE T_STRING_ANGLE { - $$ = context->HandleInclude(*$2, true, @$); + $$ = new IncludeExpression(Utility::DirName(context->GetPath()), MakeLiteral(*$2), NULL, NULL, IncludeRegular, true, context->GetZone(), context->GetPackage(), @$); delete $2; } - | T_INCLUDE_RECURSIVE T_STRING + | T_INCLUDE_RECURSIVE rterm { - $$ = context->HandleIncludeRecursive(*$2, "*.conf", @$); - delete $2; + $$ = new IncludeExpression(Utility::DirName(context->GetPath()), $2, MakeLiteral("*.conf"), NULL, IncludeRecursive, false, context->GetZone(), context->GetPackage(), @$); } - | T_INCLUDE_RECURSIVE T_STRING ',' T_STRING + | T_INCLUDE_RECURSIVE rterm ',' rterm { - $$ = context->HandleIncludeRecursive(*$2, *$4, @$); - delete $2; - delete $4; + $$ = new IncludeExpression(Utility::DirName(context->GetPath()), $2, $4, NULL, IncludeRecursive, false, context->GetZone(), context->GetPackage(), @$); } - | T_INCLUDE_ZONES T_STRING ',' T_STRING + | T_INCLUDE_ZONES rterm ',' rterm { - $$ = context->HandleIncludeZones(*$2, *$4, "*.conf", @$); - delete $2; - delete $4; + $$ = new IncludeExpression(Utility::DirName(context->GetPath()), $4, MakeLiteral("*.conf"), $2, IncludeZones, false, context->GetZone(), context->GetPackage(), @$); } - | T_INCLUDE_ZONES T_STRING ',' T_STRING ',' T_STRING + | T_INCLUDE_ZONES rterm ',' rterm ',' rterm { - $$ = context->HandleIncludeZones(*$2, *$4, *$6, @$); - delete $2; - delete $4; - delete $6; + $$ = new IncludeExpression(Utility::DirName(context->GetPath()), $4, $6, $2, IncludeZones, false, context->GetZone(), context->GetPackage(), @$); } | T_IMPORT rterm { diff --git a/lib/config/configcompiler.cpp b/lib/config/configcompiler.cpp index 412801a87d8..12ce409188e 100644 --- a/lib/config/configcompiler.cpp +++ b/lib/config/configcompiler.cpp @@ -119,24 +119,26 @@ void ConfigCompiler::CollectIncludes(std::vector& expressions, /** * Handles an include directive. * - * @param include The path from the include directive. + * @param relativeBath The path this include is relative to. + * @param path The path from the include directive. * @param search Whether to search global include dirs. * @param debuginfo Debug information. */ -Expression *ConfigCompiler::HandleInclude(const String& include, bool search, const DebugInfo& debuginfo) +Expression *ConfigCompiler::HandleInclude(const String& relativeBase, const String& path, + bool search, const String& zone, const String& package, const DebugInfo& debuginfo) { - String path; + String upath; - if (search || (include.GetLength() > 0 && include[0] == '/')) - path = include; + if (search || (path.GetLength() > 0 && path[0] == '/')) + upath = path; else - path = Utility::DirName(GetPath()) + "/" + include; + upath = relativeBase + "/" + path; - String includePath = path; + String includePath = upath; if (search) { BOOST_FOREACH(const String& dir, m_IncludeSearchDirs) { - String spath = dir + "/" + include; + String spath = dir + "/" + path; if (Utility::PathExists(spath)) { includePath = spath; @@ -147,9 +149,9 @@ Expression *ConfigCompiler::HandleInclude(const String& include, bool search, co std::vector expressions; - if (!Utility::Glob(includePath, boost::bind(&ConfigCompiler::CollectIncludes, boost::ref(expressions), _1, m_Zone, m_Package), GlobFile) && includePath.FindFirstOf("*?") == String::NPos) { + if (!Utility::Glob(includePath, boost::bind(&ConfigCompiler::CollectIncludes, boost::ref(expressions), _1, zone, package), GlobFile) && includePath.FindFirstOf("*?") == String::NPos) { std::ostringstream msgbuf; - msgbuf << "Include file '" + include + "' does not exist"; + msgbuf << "Include file '" + path + "' does not exist"; BOOST_THROW_EXCEPTION(ScriptError(msgbuf.str(), debuginfo)); } @@ -161,25 +163,27 @@ Expression *ConfigCompiler::HandleInclude(const String& include, bool search, co /** * Handles recursive includes. * + * @param relativeBase The path this include is relative to. * @param path The directory path. * @param pattern The file pattern. * @param debuginfo Debug information. */ -Expression *ConfigCompiler::HandleIncludeRecursive(const String& path, const String& pattern, const DebugInfo&) +Expression *ConfigCompiler::HandleIncludeRecursive(const String& relativeBase, const String& path, + const String& pattern, const String& zone, const String& package, const DebugInfo&) { String ppath; if (path.GetLength() > 0 && path[0] == '/') ppath = path; else - ppath = Utility::DirName(GetPath()) + "/" + path; + ppath = relativeBase + "/" + path; std::vector expressions; - Utility::GlobRecursive(ppath, pattern, boost::bind(&ConfigCompiler::CollectIncludes, boost::ref(expressions), _1, m_Zone, m_Package), GlobFile); + Utility::GlobRecursive(ppath, pattern, boost::bind(&ConfigCompiler::CollectIncludes, boost::ref(expressions), _1, zone, package), GlobFile); return new DictExpression(expressions); } -void ConfigCompiler::HandleIncludeZone(const String& tag, const String& path, const String& pattern, std::vector& expressions) +void ConfigCompiler::HandleIncludeZone(const String& relativeBase, const String& tag, const String& path, const String& pattern, const String& package, std::vector& expressions) { String zoneName = Utility::BaseName(path); @@ -188,32 +192,34 @@ void ConfigCompiler::HandleIncludeZone(const String& tag, const String& path, co if (path.GetLength() > 0 && path[0] == '/') ppath = path; else - ppath = Utility::DirName(GetPath()) + "/" + path; + ppath = relativeBase + "/" + path; RegisterZoneDir(tag, ppath, zoneName); - Utility::GlobRecursive(ppath, pattern, boost::bind(&ConfigCompiler::CollectIncludes, boost::ref(expressions), _1, zoneName, m_Package), GlobFile); + Utility::GlobRecursive(ppath, pattern, boost::bind(&ConfigCompiler::CollectIncludes, boost::ref(expressions), _1, zoneName, package), GlobFile); } /** * Handles zone includes. * + * @param relativeBase The path this include is relative to. * @param tag The tag name. * @param path The directory path. * @param pattern The file pattern. * @param debuginfo Debug information. */ -Expression *ConfigCompiler::HandleIncludeZones(const String& tag, const String& path, const String& pattern, const DebugInfo&) +Expression *ConfigCompiler::HandleIncludeZones(const String& relativeBase, const String& tag, + const String& path, const String& pattern, const String& package, const DebugInfo&) { String ppath; if (path.GetLength() > 0 && path[0] == '/') ppath = path; else - ppath = Utility::DirName(GetPath()) + "/" + path; + ppath = relativeBase + "/" + path; std::vector expressions; - Utility::Glob(ppath + "/*", boost::bind(&ConfigCompiler::HandleIncludeZone, this, tag, _1, pattern, boost::ref(expressions)), GlobDirectory); + Utility::Glob(ppath + "/*", boost::bind(&ConfigCompiler::HandleIncludeZone, relativeBase, tag, _1, pattern, package, boost::ref(expressions)), GlobDirectory); return new DictExpression(expressions); } diff --git a/lib/config/configcompiler.hpp b/lib/config/configcompiler.hpp index b216b12a198..66e8df177f6 100644 --- a/lib/config/configcompiler.hpp +++ b/lib/config/configcompiler.hpp @@ -105,10 +105,12 @@ class I2_CONFIG_API ConfigCompiler static void CollectIncludes(std::vector& expressions, const String& file, const String& zone, const String& package); - /* internally used methods */ - Expression *HandleInclude(const String& include, bool search, const DebugInfo& debuginfo = DebugInfo()); - Expression *HandleIncludeRecursive(const String& path, const String& pattern, const DebugInfo& debuginfo = DebugInfo()); - Expression *HandleIncludeZones(const String& tag, const String& path, const String& pattern, const DebugInfo& debuginfo = DebugInfo()); + static Expression *HandleInclude(const String& relativeBase, const String& path, bool search, + const String& zone, const String& package, const DebugInfo& debuginfo = DebugInfo()); + static Expression *HandleIncludeRecursive(const String& relativeBase, const String& path, + const String& pattern, const String& zone, const String& package, const DebugInfo& debuginfo = DebugInfo()); + static Expression *HandleIncludeZones(const String& relativeBase, const String& tag, + const String& path, const String& pattern, const String& package, const DebugInfo& debuginfo = DebugInfo()); size_t ReadInput(char *buffer, size_t max_bytes); void *GetScanner(void) const; @@ -135,7 +137,7 @@ class I2_CONFIG_API ConfigCompiler void InitializeScanner(void); void DestroyScanner(void); - void HandleIncludeZone(const String& tag, const String& path, const String& pattern, std::vector& expressions); + static void HandleIncludeZone(const String& relativeBase, const String& tag, const String& path, const String& pattern, const String& package, std::vector& expressions); public: bool m_Eof; diff --git a/lib/config/expression.cpp b/lib/config/expression.cpp index f1679a84cb4..1c4dcea293d 100644 --- a/lib/config/expression.cpp +++ b/lib/config/expression.cpp @@ -19,6 +19,7 @@ #include "config/expression.hpp" #include "config/configitem.hpp" +#include "config/configcompiler.hpp" #include "config/vmops.hpp" #include "base/array.hpp" #include "base/json.hpp" @@ -783,3 +784,74 @@ ExpressionResult LibraryExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dh return Empty; } +ExpressionResult IncludeExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const +{ + if (frame.Sandboxed) + BOOST_THROW_EXCEPTION(ScriptError("Includes are not allowed in sandbox mode.", m_DebugInfo)); + + Expression *expr; + String name, path, pattern; + + switch (m_Type) { + case IncludeRegular: + { + ExpressionResult pathres = m_Path->Evaluate(frame, dhint); + CHECK_RESULT(pathres); + path = pathres.GetValue(); + } + + expr = ConfigCompiler::HandleInclude(m_RelativeBase, path, m_SearchIncludes, m_Zone, m_Package, m_DebugInfo); + break; + + case IncludeRecursive: + { + ExpressionResult pathres = m_Path->Evaluate(frame, dhint); + CHECK_RESULT(pathres); + path = pathres.GetValue(); + } + + { + ExpressionResult patternres = m_Pattern->Evaluate(frame, dhint); + CHECK_RESULT(patternres); + pattern = patternres.GetValue(); + } + + expr = ConfigCompiler::HandleIncludeRecursive(m_RelativeBase, path, pattern, m_Zone, m_Package, m_DebugInfo); + break; + + case IncludeZones: + { + ExpressionResult nameres = m_Name->Evaluate(frame, dhint); + CHECK_RESULT(nameres); + name = nameres.GetValue(); + } + + { + ExpressionResult pathres = m_Path->Evaluate(frame, dhint); + CHECK_RESULT(pathres); + path = pathres.GetValue(); + } + + { + ExpressionResult patternres = m_Pattern->Evaluate(frame, dhint); + CHECK_RESULT(patternres); + pattern = patternres.GetValue(); + } + + expr = ConfigCompiler::HandleIncludeZones(m_RelativeBase, name, path, pattern, m_Package, m_DebugInfo); + break; + } + + ExpressionResult res(Empty); + + try { + res = expr->Evaluate(frame, dhint); + } catch (const std::exception&) { + delete expr; + throw; + } + + delete expr; + + return res; +} diff --git a/lib/config/expression.hpp b/lib/config/expression.hpp index dba2db3ae22..130edf5a5d7 100644 --- a/lib/config/expression.hpp +++ b/lib/config/expression.hpp @@ -899,6 +899,43 @@ class I2_CONFIG_API LibraryExpression : public UnaryExpression virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; }; +enum IncludeType +{ + IncludeRegular, + IncludeRecursive, + IncludeZones +}; + +class I2_CONFIG_API IncludeExpression : public DebuggableExpression +{ +public: + IncludeExpression(const String& relativeBase, Expression *path, Expression *pattern, Expression *name, + IncludeType type, bool searchIncludes, const String& zone, const String& package, const DebugInfo& debugInfo = DebugInfo()) + : DebuggableExpression(debugInfo), m_RelativeBase(relativeBase), m_Path(path), m_Pattern(pattern), + m_Name(name), m_Type(type), m_SearchIncludes(searchIncludes), m_Zone(zone), m_Package(package) + { } + + ~IncludeExpression(void) + { + delete m_Path; + delete m_Pattern; + delete m_Name; + } + +protected: + virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; + +private: + String m_RelativeBase; + Expression *m_Path; + Expression *m_Pattern; + Expression *m_Name; + IncludeType m_Type; + bool m_SearchIncludes; + String m_Zone; + String m_Package; +}; + } #endif /* EXPRESSION_H */