Turn includes into AST expressions

fixes #10008
This commit is contained in:
Gunnar Beutner 2015-10-22 09:46:31 +02:00
parent fd5d6de52e
commit 74ef3e3ce6
5 changed files with 152 additions and 44 deletions

View File

@ -443,39 +443,30 @@ lterm: T_LIBRARY rterm
{ {
$$ = new SetExpression($1, $2, $3, @$); $$ = new SetExpression($1, $2, $3, @$);
} }
| T_INCLUDE T_STRING | T_INCLUDE rterm
{ {
$$ = context->HandleInclude(*$2, false, @$); $$ = new IncludeExpression(Utility::DirName(context->GetPath()), $2, NULL, NULL, IncludeRegular, false, context->GetZone(), context->GetPackage(), @$);
delete $2;
} }
| T_INCLUDE T_STRING_ANGLE | 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; delete $2;
} }
| T_INCLUDE_RECURSIVE T_STRING | T_INCLUDE_RECURSIVE rterm
{ {
$$ = context->HandleIncludeRecursive(*$2, "*.conf", @$); $$ = new IncludeExpression(Utility::DirName(context->GetPath()), $2, MakeLiteral("*.conf"), NULL, IncludeRecursive, false, context->GetZone(), context->GetPackage(), @$);
delete $2;
} }
| T_INCLUDE_RECURSIVE T_STRING ',' T_STRING | T_INCLUDE_RECURSIVE rterm ',' rterm
{ {
$$ = context->HandleIncludeRecursive(*$2, *$4, @$); $$ = new IncludeExpression(Utility::DirName(context->GetPath()), $2, $4, NULL, IncludeRecursive, false, context->GetZone(), context->GetPackage(), @$);
delete $2;
delete $4;
} }
| T_INCLUDE_ZONES T_STRING ',' T_STRING | T_INCLUDE_ZONES rterm ',' rterm
{ {
$$ = context->HandleIncludeZones(*$2, *$4, "*.conf", @$); $$ = new IncludeExpression(Utility::DirName(context->GetPath()), $4, MakeLiteral("*.conf"), $2, IncludeZones, false, context->GetZone(), context->GetPackage(), @$);
delete $2;
delete $4;
} }
| T_INCLUDE_ZONES T_STRING ',' T_STRING ',' T_STRING | T_INCLUDE_ZONES rterm ',' rterm ',' rterm
{ {
$$ = context->HandleIncludeZones(*$2, *$4, *$6, @$); $$ = new IncludeExpression(Utility::DirName(context->GetPath()), $4, $6, $2, IncludeZones, false, context->GetZone(), context->GetPackage(), @$);
delete $2;
delete $4;
delete $6;
} }
| T_IMPORT rterm | T_IMPORT rterm
{ {

View File

@ -119,24 +119,26 @@ void ConfigCompiler::CollectIncludes(std::vector<Expression *>& expressions,
/** /**
* Handles an include directive. * 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 search Whether to search global include dirs.
* @param debuginfo Debug information. * @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] == '/')) if (search || (path.GetLength() > 0 && path[0] == '/'))
path = include; upath = path;
else else
path = Utility::DirName(GetPath()) + "/" + include; upath = relativeBase + "/" + path;
String includePath = path; String includePath = upath;
if (search) { if (search) {
BOOST_FOREACH(const String& dir, m_IncludeSearchDirs) { BOOST_FOREACH(const String& dir, m_IncludeSearchDirs) {
String spath = dir + "/" + include; String spath = dir + "/" + path;
if (Utility::PathExists(spath)) { if (Utility::PathExists(spath)) {
includePath = spath; includePath = spath;
@ -147,9 +149,9 @@ Expression *ConfigCompiler::HandleInclude(const String& include, bool search, co
std::vector<Expression *> expressions; std::vector<Expression *> 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; std::ostringstream msgbuf;
msgbuf << "Include file '" + include + "' does not exist"; msgbuf << "Include file '" + path + "' does not exist";
BOOST_THROW_EXCEPTION(ScriptError(msgbuf.str(), debuginfo)); BOOST_THROW_EXCEPTION(ScriptError(msgbuf.str(), debuginfo));
} }
@ -161,25 +163,27 @@ Expression *ConfigCompiler::HandleInclude(const String& include, bool search, co
/** /**
* Handles recursive includes. * Handles recursive includes.
* *
* @param relativeBase The path this include is relative to.
* @param path The directory path. * @param path The directory path.
* @param pattern The file pattern. * @param pattern The file pattern.
* @param debuginfo Debug information. * @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; String ppath;
if (path.GetLength() > 0 && path[0] == '/') if (path.GetLength() > 0 && path[0] == '/')
ppath = path; ppath = path;
else else
ppath = Utility::DirName(GetPath()) + "/" + path; ppath = relativeBase + "/" + path;
std::vector<Expression *> expressions; std::vector<Expression *> 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); return new DictExpression(expressions);
} }
void ConfigCompiler::HandleIncludeZone(const String& tag, const String& path, const String& pattern, std::vector<Expression *>& expressions) void ConfigCompiler::HandleIncludeZone(const String& relativeBase, const String& tag, const String& path, const String& pattern, const String& package, std::vector<Expression *>& expressions)
{ {
String zoneName = Utility::BaseName(path); 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] == '/') if (path.GetLength() > 0 && path[0] == '/')
ppath = path; ppath = path;
else else
ppath = Utility::DirName(GetPath()) + "/" + path; ppath = relativeBase + "/" + path;
RegisterZoneDir(tag, ppath, zoneName); 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. * Handles zone includes.
* *
* @param relativeBase The path this include is relative to.
* @param tag The tag name. * @param tag The tag name.
* @param path The directory path. * @param path The directory path.
* @param pattern The file pattern. * @param pattern The file pattern.
* @param debuginfo Debug information. * @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; String ppath;
if (path.GetLength() > 0 && path[0] == '/') if (path.GetLength() > 0 && path[0] == '/')
ppath = path; ppath = path;
else else
ppath = Utility::DirName(GetPath()) + "/" + path; ppath = relativeBase + "/" + path;
std::vector<Expression *> expressions; std::vector<Expression *> 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); return new DictExpression(expressions);
} }

View File

@ -105,10 +105,12 @@ public:
static void CollectIncludes(std::vector<Expression *>& expressions, static void CollectIncludes(std::vector<Expression *>& expressions,
const String& file, const String& zone, const String& package); const String& file, const String& zone, const String& package);
/* internally used methods */ static Expression *HandleInclude(const String& relativeBase, const String& path, bool search,
Expression *HandleInclude(const String& include, bool search, const DebugInfo& debuginfo = DebugInfo()); const String& zone, const String& package, const DebugInfo& debuginfo = DebugInfo());
Expression *HandleIncludeRecursive(const String& path, const String& pattern, const DebugInfo& debuginfo = DebugInfo()); static Expression *HandleIncludeRecursive(const String& relativeBase, const String& path,
Expression *HandleIncludeZones(const String& tag, const String& path, const String& pattern, const DebugInfo& debuginfo = DebugInfo()); 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); size_t ReadInput(char *buffer, size_t max_bytes);
void *GetScanner(void) const; void *GetScanner(void) const;
@ -135,7 +137,7 @@ private:
void InitializeScanner(void); void InitializeScanner(void);
void DestroyScanner(void); void DestroyScanner(void);
void HandleIncludeZone(const String& tag, const String& path, const String& pattern, std::vector<Expression *>& expressions); static void HandleIncludeZone(const String& relativeBase, const String& tag, const String& path, const String& pattern, const String& package, std::vector<Expression *>& expressions);
public: public:
bool m_Eof; bool m_Eof;

View File

@ -19,6 +19,7 @@
#include "config/expression.hpp" #include "config/expression.hpp"
#include "config/configitem.hpp" #include "config/configitem.hpp"
#include "config/configcompiler.hpp"
#include "config/vmops.hpp" #include "config/vmops.hpp"
#include "base/array.hpp" #include "base/array.hpp"
#include "base/json.hpp" #include "base/json.hpp"
@ -783,3 +784,74 @@ ExpressionResult LibraryExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dh
return Empty; 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;
}

View File

@ -899,6 +899,43 @@ protected:
virtual ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; 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 */ #endif /* EXPRESSION_H */