diff --git a/doc/4.1-configuration-syntax.md b/doc/4.1-configuration-syntax.md index f8a869cbd..433736843 100644 --- a/doc/4.1-configuration-syntax.md +++ b/doc/4.1-configuration-syntax.md @@ -320,7 +320,7 @@ Simple calculations can be performed using the constant expression syntax: check_interval = 30 + 60 } -Valid operators include ~, +, -, *, /, ==, !=, in and !in. The default precedence rules can be +Valid operators include ~, !, +, -, *, /, ==, !=, in and !in. The default precedence rules can be overridden by grouping expressions using parentheses: { diff --git a/lib/base/qstring.cpp b/lib/base/qstring.cpp index 0ba16b699..5aba2f808 100644 --- a/lib/base/qstring.cpp +++ b/lib/base/qstring.cpp @@ -136,6 +136,11 @@ std::string& String::GetData(void) return m_Data; } +const std::string& String::GetData(void) const +{ + return m_Data; +} + size_t String::Find(const String& str, size_t pos) const { return m_Data.find(str, pos); diff --git a/lib/base/qstring.h b/lib/base/qstring.h index 7464c2e68..b85800312 100644 --- a/lib/base/qstring.h +++ b/lib/base/qstring.h @@ -80,6 +80,7 @@ public: size_t GetLength(void) const; std::string& GetData(void); + const std::string& GetData(void) const; size_t Find(const String& str, size_t pos = 0) const; size_t RFind(const String& str, size_t pos = NPos) const; diff --git a/lib/config/aexpression.cpp b/lib/config/aexpression.cpp index 637b46d0e..40dbadea8 100644 --- a/lib/config/aexpression.cpp +++ b/lib/config/aexpression.cpp @@ -21,6 +21,7 @@ #include "base/array.h" #include "base/serializer.h" #include "base/context.h" +#include "base/scriptfunction.h" #include using namespace icinga; @@ -35,14 +36,19 @@ AExpression::AExpression(AOperator op, const AValue& operand1, const AValue& ope : m_Operator(op), m_Operand1(operand1), m_Operand2(operand2), m_DebugInfo(di) { ASSERT(op == AEAdd || op == AENegate || op == AESubtract || op == AEMultiply || op == AEDivide || - op == AEBinaryAnd || op == AEBinaryOr || op == AEShiftLeft || op == AEShiftRight); + op == AEBinaryAnd || op == AEBinaryOr || op == AEShiftLeft || op == AEShiftRight || + op == AEEqual || op == AENotEqual || op == AEIn || op == AENotIn || + op == AELogicalAnd || op == AELogicalOr || op == AEFunctionCall); } Value AExpression::Evaluate(const Dictionary::Ptr& locals) const { Value left, right; - Array::Ptr arr; + Array::Ptr arr, arr2; bool found; + String funcName; + ScriptFunction::Ptr func; + std::vector arguments; left = m_Operand1.Evaluate(locals); right = m_Operand2.Evaluate(locals); @@ -111,8 +117,29 @@ Value AExpression::Evaluate(const Dictionary::Ptr& locals) const return (long)left && (long)right; case AELogicalOr: return (long)left || (long)right; + case AEFunctionCall: + funcName = left; + func = ScriptFunctionRegistry::GetInstance()->GetItem(funcName); + + if (!func) + BOOST_THROW_EXCEPTION(std::invalid_argument("Function '" + funcName + "' does not exist.")); + + arr = right; + BOOST_FOREACH(const AExpression::Ptr& aexpr, arr) { + arguments.push_back(aexpr->Evaluate(locals)); + } + + return func->Invoke(arguments); + case AEArray: + arr = left; + arr2 = make_shared(); + + BOOST_FOREACH(const AExpression::Ptr& aexpr, arr) { + arr2->Add(aexpr->Evaluate(locals)); + } + + return arr2; default: ASSERT(!"Invalid operator."); } } - diff --git a/lib/config/aexpression.h b/lib/config/aexpression.h index f78afe598..a2dd99c12 100644 --- a/lib/config/aexpression.h +++ b/lib/config/aexpression.h @@ -48,7 +48,9 @@ enum AOperator AEIn, AENotIn, AELogicalAnd, - AELogicalOr + AELogicalOr, + AEFunctionCall, + AEArray }; /** diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy index 749b3aafe..f508747a6 100644 --- a/lib/config/config_parser.yy +++ b/lib/config/config_parser.yy @@ -108,10 +108,8 @@ using namespace icinga; %token T_TO "to (T_TO)" %token T_WHERE "where (T_WHERE)" %type identifier -%type array %type array_items %type array_items_inner -%type simplevalue %type value %type expression %type expressions @@ -135,6 +133,8 @@ using namespace icinga; %left '*' '/' %left '&' %left '|' +%right '~' +%right '!' %{ int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner); @@ -506,12 +506,6 @@ operator: T_SET } ; -array: '[' array_items ']' - { - $$ = $2; - } - ; - array_items: array_items_inner { $$ = $1; @@ -525,79 +519,62 @@ array_items_inner: /* empty */ { $$ = NULL; } - | value + | aexpression { $$ = new Array(); - - if ($1->IsObjectType()) { - ExpressionList::Ptr exprl = *$1; - Dictionary::Ptr dict = make_shared(); - exprl->Execute(dict); - delete $1; - $1 = new Value(dict); - } - $$->Add(*$1); delete $1; } - | array_items_inner ',' value + | array_items_inner ',' aexpression { if ($1) $$ = $1; else $$ = new Array(); - if ($3->IsObjectType()) { - ExpressionList::Ptr exprl = *$3; - Dictionary::Ptr dict = make_shared(); - exprl->Execute(dict); - delete $3; - $3 = new Value(dict); - } - $$->Add(*$3); delete $3; } ; -simplevalue: T_STRING +aexpression: T_STRING { - $$ = new Value($1); + $$ = new Value(make_shared(AEReturn, AValue(ATSimple, $1), yylloc)); free($1); } | T_NUMBER { - $$ = new Value($1); + $$ = new Value(make_shared(AEReturn, AValue(ATSimple, $1), yylloc)); } | T_NULL { - $$ = new Value(); + $$ = new Value(make_shared(AEReturn, AValue(ATSimple, Empty), yylloc)); } - | array + | T_IDENTIFIER '(' array_items ')' { - if ($1 == NULL) - $1 = new Array(); - - Array::Ptr array = Array::Ptr($1); - $$ = new Value(array); - } - ; - -aexpression: simplevalue - { - $$ = new Value(make_shared(AEReturn, AValue(ATSimple, *$1), yylloc)); - delete $1; + Array::Ptr arguments = Array::Ptr($3); + $$ = new Value(make_shared(AEFunctionCall, AValue(ATSimple, $1), AValue(ATSimple, arguments), yylloc)); + free($1); } | T_IDENTIFIER { $$ = new Value(make_shared(AEReturn, AValue(ATVariable, $1), yylloc)); free($1); } + | '!' aexpression + { + $$ = new Value(make_shared(AENegate, static_cast(*$2), yylloc)); + delete $2; + } | '~' aexpression { $$ = new Value(make_shared(AENegate, static_cast(*$2), yylloc)); delete $2; } + | '[' array_items ']' + { + $$ = new Value(make_shared(AEArray, AValue(ATSimple, Array::Ptr($2)), yylloc)); + } | '(' aexpression ')' { $$ = $2; @@ -688,8 +665,7 @@ aexpression: simplevalue } ; -value: simplevalue - | expressionlist +value: expressionlist { ExpressionList::Ptr exprl = ExpressionList::Ptr($1); $$ = new Value(exprl); diff --git a/lib/methods/CMakeLists.txt b/lib/methods/CMakeLists.txt index a689d4e9d..281c0a88d 100644 --- a/lib/methods/CMakeLists.txt +++ b/lib/methods/CMakeLists.txt @@ -18,7 +18,7 @@ add_library(methods SHARED icingachecktask.cpp nullchecktask.cpp nulleventtask.cpp pluginchecktask.cpp plugineventtask.cpp pluginnotificationtask.cpp - randomchecktask.cpp timeperiodtask.cpp + randomchecktask.cpp timeperiodtask.cpp utilityfuncs.cpp ) target_link_libraries(methods ${Boost_LIBRARIES} base config icinga) diff --git a/lib/methods/utilityfuncs.cpp b/lib/methods/utilityfuncs.cpp new file mode 100644 index 000000000..298b597e8 --- /dev/null +++ b/lib/methods/utilityfuncs.cpp @@ -0,0 +1,35 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012-present Icinga Development Team (http://www.icinga.org) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#include "methods/utilityfuncs.h" +#include "base/scriptfunction.h" +#include "base/utility.h" +#include + +using namespace icinga; + +REGISTER_SCRIPTFUNCTION(regex, &UtilityFuncs::Regex); +REGISTER_SCRIPTFUNCTION(match, &Utility::Match); + +bool UtilityFuncs::Regex(const String& pattern, const String& text) +{ + boost::regex expr(pattern.GetData()); + boost::smatch what; + return boost::regex_search(text.GetData(), what, expr); +} diff --git a/lib/methods/utilityfuncs.h b/lib/methods/utilityfuncs.h new file mode 100644 index 000000000..7612672be --- /dev/null +++ b/lib/methods/utilityfuncs.h @@ -0,0 +1,43 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012-present Icinga Development Team (http://www.icinga.org) * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License * + * as published by the Free Software Foundation; either version 2 * + * of the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software Foundation * + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * + ******************************************************************************/ + +#ifndef UTILITYFUNCS_H +#define UTILITYFUNCS_H + +#include "methods/i2-methods.h" +#include "base/qstring.h" + +namespace icinga +{ + +/** + * @ingroup methods + */ +class I2_METHODS_API UtilityFuncs +{ +public: + static bool Regex(const String& pattern, const String& text); + +private: + UtilityFuncs(void); +}; + +} + +#endif /* UTILITYFUNCS_H */