Implement regex() and match() functions.

Refs #5789
This commit is contained in:
Gunnar Beutner 2014-03-19 10:51:09 +01:00
parent 124fa9ebc1
commit 3383951791
9 changed files with 141 additions and 52 deletions

View File

@ -320,7 +320,7 @@ Simple calculations can be performed using the constant expression syntax:
check_interval = 30 + 60 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: overridden by grouping expressions using parentheses:
{ {

View File

@ -136,6 +136,11 @@ std::string& String::GetData(void)
return m_Data; return m_Data;
} }
const std::string& String::GetData(void) const
{
return m_Data;
}
size_t String::Find(const String& str, size_t pos) const size_t String::Find(const String& str, size_t pos) const
{ {
return m_Data.find(str, pos); return m_Data.find(str, pos);

View File

@ -80,6 +80,7 @@ public:
size_t GetLength(void) const; size_t GetLength(void) const;
std::string& GetData(void); std::string& GetData(void);
const std::string& GetData(void) const;
size_t Find(const String& str, size_t pos = 0) const; size_t Find(const String& str, size_t pos = 0) const;
size_t RFind(const String& str, size_t pos = NPos) const; size_t RFind(const String& str, size_t pos = NPos) const;

View File

@ -21,6 +21,7 @@
#include "base/array.h" #include "base/array.h"
#include "base/serializer.h" #include "base/serializer.h"
#include "base/context.h" #include "base/context.h"
#include "base/scriptfunction.h"
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
using namespace icinga; 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) : m_Operator(op), m_Operand1(operand1), m_Operand2(operand2), m_DebugInfo(di)
{ {
ASSERT(op == AEAdd || op == AENegate || op == AESubtract || op == AEMultiply || op == AEDivide || 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 AExpression::Evaluate(const Dictionary::Ptr& locals) const
{ {
Value left, right; Value left, right;
Array::Ptr arr; Array::Ptr arr, arr2;
bool found; bool found;
String funcName;
ScriptFunction::Ptr func;
std::vector<Value> arguments;
left = m_Operand1.Evaluate(locals); left = m_Operand1.Evaluate(locals);
right = m_Operand2.Evaluate(locals); right = m_Operand2.Evaluate(locals);
@ -111,8 +117,29 @@ Value AExpression::Evaluate(const Dictionary::Ptr& locals) const
return (long)left && (long)right; return (long)left && (long)right;
case AELogicalOr: case AELogicalOr:
return (long)left || (long)right; 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<Array>();
BOOST_FOREACH(const AExpression::Ptr& aexpr, arr) {
arr2->Add(aexpr->Evaluate(locals));
}
return arr2;
default: default:
ASSERT(!"Invalid operator."); ASSERT(!"Invalid operator.");
} }
} }

View File

@ -48,7 +48,9 @@ enum AOperator
AEIn, AEIn,
AENotIn, AENotIn,
AELogicalAnd, AELogicalAnd,
AELogicalOr AELogicalOr,
AEFunctionCall,
AEArray
}; };
/** /**

View File

@ -108,10 +108,8 @@ using namespace icinga;
%token T_TO "to (T_TO)" %token T_TO "to (T_TO)"
%token T_WHERE "where (T_WHERE)" %token T_WHERE "where (T_WHERE)"
%type <text> identifier %type <text> identifier
%type <array> array
%type <array> array_items %type <array> array_items
%type <array> array_items_inner %type <array> array_items_inner
%type <variant> simplevalue
%type <variant> value %type <variant> value
%type <expr> expression %type <expr> expression
%type <exprl> expressions %type <exprl> expressions
@ -135,6 +133,8 @@ using namespace icinga;
%left '*' '/' %left '*' '/'
%left '&' %left '&'
%left '|' %left '|'
%right '~'
%right '!'
%{ %{
int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner); int yylex(YYSTYPE *lvalp, YYLTYPE *llocp, void *scanner);
@ -506,12 +506,6 @@ operator: T_SET
} }
; ;
array: '[' array_items ']'
{
$$ = $2;
}
;
array_items: array_items_inner array_items: array_items_inner
{ {
$$ = $1; $$ = $1;
@ -525,79 +519,62 @@ array_items_inner: /* empty */
{ {
$$ = NULL; $$ = NULL;
} }
| value | aexpression
{ {
$$ = new Array(); $$ = new Array();
if ($1->IsObjectType<ExpressionList>()) {
ExpressionList::Ptr exprl = *$1;
Dictionary::Ptr dict = make_shared<Dictionary>();
exprl->Execute(dict);
delete $1;
$1 = new Value(dict);
}
$$->Add(*$1); $$->Add(*$1);
delete $1; delete $1;
} }
| array_items_inner ',' value | array_items_inner ',' aexpression
{ {
if ($1) if ($1)
$$ = $1; $$ = $1;
else else
$$ = new Array(); $$ = new Array();
if ($3->IsObjectType<ExpressionList>()) {
ExpressionList::Ptr exprl = *$3;
Dictionary::Ptr dict = make_shared<Dictionary>();
exprl->Execute(dict);
delete $3;
$3 = new Value(dict);
}
$$->Add(*$3); $$->Add(*$3);
delete $3; delete $3;
} }
; ;
simplevalue: T_STRING aexpression: T_STRING
{ {
$$ = new Value($1); $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATSimple, $1), yylloc));
free($1); free($1);
} }
| T_NUMBER | T_NUMBER
{ {
$$ = new Value($1); $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATSimple, $1), yylloc));
} }
| T_NULL | T_NULL
{ {
$$ = new Value(); $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATSimple, Empty), yylloc));
} }
| array | T_IDENTIFIER '(' array_items ')'
{ {
if ($1 == NULL) Array::Ptr arguments = Array::Ptr($3);
$1 = new Array(); $$ = new Value(make_shared<AExpression>(AEFunctionCall, AValue(ATSimple, $1), AValue(ATSimple, arguments), yylloc));
free($1);
Array::Ptr array = Array::Ptr($1);
$$ = new Value(array);
}
;
aexpression: simplevalue
{
$$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATSimple, *$1), yylloc));
delete $1;
} }
| T_IDENTIFIER | T_IDENTIFIER
{ {
$$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATVariable, $1), yylloc)); $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATVariable, $1), yylloc));
free($1); free($1);
} }
| '!' aexpression
{
$$ = new Value(make_shared<AExpression>(AENegate, static_cast<AExpression::Ptr>(*$2), yylloc));
delete $2;
}
| '~' aexpression | '~' aexpression
{ {
$$ = new Value(make_shared<AExpression>(AENegate, static_cast<AExpression::Ptr>(*$2), yylloc)); $$ = new Value(make_shared<AExpression>(AENegate, static_cast<AExpression::Ptr>(*$2), yylloc));
delete $2; delete $2;
} }
| '[' array_items ']'
{
$$ = new Value(make_shared<AExpression>(AEArray, AValue(ATSimple, Array::Ptr($2)), yylloc));
}
| '(' aexpression ')' | '(' aexpression ')'
{ {
$$ = $2; $$ = $2;
@ -688,8 +665,7 @@ aexpression: simplevalue
} }
; ;
value: simplevalue value: expressionlist
| expressionlist
{ {
ExpressionList::Ptr exprl = ExpressionList::Ptr($1); ExpressionList::Ptr exprl = ExpressionList::Ptr($1);
$$ = new Value(exprl); $$ = new Value(exprl);

View File

@ -18,7 +18,7 @@
add_library(methods SHARED add_library(methods SHARED
icingachecktask.cpp nullchecktask.cpp nulleventtask.cpp icingachecktask.cpp nullchecktask.cpp nulleventtask.cpp
pluginchecktask.cpp plugineventtask.cpp pluginnotificationtask.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) target_link_libraries(methods ${Boost_LIBRARIES} base config icinga)

View File

@ -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 <boost/regex.hpp>
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);
}

View File

@ -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 */