From 0503c3cea098a1ec25c35b4fb261039406d02d09 Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Sun, 6 Apr 2014 19:42:43 +0200 Subject: [PATCH] core, frontend: Added !=, !~, and NOT operators. --- src/core/store_lookup.c | 40 ++++++++++++++++++++++++++++++-------- src/frontend/grammar.y | 31 +++++++++++++++++++++++++---- src/frontend/scanner.l | 2 ++ t/core/store_lookup_test.c | 12 +++++++++++- 4 files changed, 72 insertions(+), 13 deletions(-) diff --git a/src/core/store_lookup.c b/src/core/store_lookup.c index d43b9e3..7416800 100644 --- a/src/core/store_lookup.c +++ b/src/core/store_lookup.c @@ -514,6 +514,9 @@ sdb_store_matcher_parse_cmp(const char *obj_type, const char *attr, const char *op, const char *value) { int typ = -1; + int inv = 0; + + sdb_store_matcher_t *m = NULL; const char *matcher = NULL; const char *matcher_re = NULL; @@ -526,10 +529,20 @@ sdb_store_matcher_parse_cmp(const char *obj_type, const char *attr, typ = SDB_ATTRIBUTE; /* TODO: support other operators */ - if (! strcasecmp(op, "=")) + if (! strcasecmp(op, "=")) { + matcher = value; + } + else if (! strcasecmp(op, "!=")) { matcher = value; - else if (! strcasecmp(op, "=~")) + inv = 1; + } + else if (! strcasecmp(op, "=~")) { matcher_re = value; + } + else if (! strcasecmp(op, "!~")) { + matcher_re = value; + inv = 1; + } else return NULL; @@ -537,17 +550,28 @@ sdb_store_matcher_parse_cmp(const char *obj_type, const char *attr, /* accept */ } else if (typ == SDB_ATTRIBUTE) - return sdb_store_attr_matcher(attr, NULL, matcher, matcher_re); + m = sdb_store_attr_matcher(attr, NULL, matcher, matcher_re); else return NULL; - if (typ == SDB_HOST) - return sdb_store_host_matcher(matcher, matcher_re, NULL, NULL); + if (m) { + /* accept the attribute value matcher */ + } + else if (typ == SDB_HOST) + m = sdb_store_host_matcher(matcher, matcher_re, NULL, NULL); else if (typ == SDB_SERVICE) - return sdb_store_service_matcher(matcher, matcher_re, NULL); + m = sdb_store_service_matcher(matcher, matcher_re, NULL); else if (typ == SDB_ATTRIBUTE) - return sdb_store_attr_matcher(matcher, matcher_re, NULL, NULL); - return NULL; + m = sdb_store_attr_matcher(matcher, matcher_re, NULL, NULL); + + if (m && inv) { + sdb_store_matcher_t *tmp; + tmp = sdb_store_inv_matcher(m); + /* pass ownership to the inverse matcher */ + sdb_object_deref(SDB_OBJ(m)); + m = tmp; + } + return m; } /* sdb_store_matcher_parse_cmp */ sdb_store_matcher_t * diff --git a/src/frontend/grammar.y b/src/frontend/grammar.y index 4bade3b..858c766 100644 --- a/src/frontend/grammar.y +++ b/src/frontend/grammar.y @@ -78,9 +78,9 @@ sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg); %token SCANNER_ERROR -%token AND OR WHERE +%token AND OR NOT WHERE -%token CMP_EQUAL CMP_REGEX +%token CMP_EQUAL CMP_NEQUAL CMP_REGEX CMP_NREGEX %token IDENTIFIER STRING %token FETCH LIST LOOKUP @@ -88,8 +88,9 @@ sdb_fe_yyerror(YYLTYPE *lval, sdb_fe_yyscan_t scanner, const char *msg); /* Precedence (lowest first): */ %left OR %left AND -%left CMP_EQUAL -%left CMP_REGEX +%left NOT +%left CMP_EQUAL CMP_NEQUAL +%left CMP_REGEX CMP_NREGEX %left '(' ')' %left '.' @@ -283,6 +284,11 @@ matcher: $$ = sdb_store_dis_matcher($1, $3); } | + NOT matcher + { + $$ = sdb_store_inv_matcher($2); + } + | compare_matcher { $$ = $1; @@ -304,6 +310,15 @@ compare_matcher: free($5); $5 = NULL; } | + IDENTIFIER '.' IDENTIFIER CMP_NEQUAL STRING + { + $$ = sdb_store_matcher_parse_cmp($1, $3, "!=", $5); + /* TODO: simplify memory management in the parser */ + free($1); $1 = NULL; + free($3); $3 = NULL; + free($5); $5 = NULL; + } + | IDENTIFIER '.' IDENTIFIER CMP_REGEX STRING { $$ = sdb_store_matcher_parse_cmp($1, $3, "=~", $5); @@ -311,6 +326,14 @@ compare_matcher: free($3); $3 = NULL; free($5); $5 = NULL; } + | + IDENTIFIER '.' IDENTIFIER CMP_NREGEX STRING + { + $$ = sdb_store_matcher_parse_cmp($1, $3, "!~", $5); + free($1); $1 = NULL; + free($3); $3 = NULL; + free($5); $5 = NULL; + } ; %% diff --git a/src/frontend/scanner.l b/src/frontend/scanner.l index 9eec4de..32c13c5 100644 --- a/src/frontend/scanner.l +++ b/src/frontend/scanner.l @@ -115,7 +115,9 @@ string ('[^']*') } = { return CMP_EQUAL; } +!= { return CMP_NEQUAL; } =~ { return CMP_REGEX; } +!~ { return CMP_NREGEX; } . { /* XXX: */ return yytext[0]; } diff --git a/t/core/store_lookup_test.c b/t/core/store_lookup_test.c index 977bd95..a16d343 100644 --- a/t/core/store_lookup_test.c +++ b/t/core/store_lookup_test.c @@ -348,17 +348,27 @@ START_TEST(test_parse_cmp) int expected; } golden_data[] = { { "host", "name", "=", "hostname", MATCHER_HOST }, + { "host", "name", "!=", "hostname", MATCHER_NOT }, { "host", "name", "=~", "hostname", MATCHER_HOST }, + { "host", "name", "!~", "hostname", MATCHER_NOT }, { "host", "attr", "=", "hostname", -1 }, + { "host", "attr", "!=", "hostname", -1 }, { "host", "name", "&^", "hostname", -1 }, { "service", "name", "=", "srvname", MATCHER_SERVICE }, - { "service", "name", "=", "srvname", MATCHER_SERVICE }, + { "service", "name", "!=", "srvname", MATCHER_NOT }, + { "service", "name", "=~", "srvname", MATCHER_SERVICE }, + { "service", "name", "!~", "srvname", MATCHER_NOT }, { "service", "attr", "=", "srvname", -1 }, + { "service", "attr", "!=", "srvname", -1 }, { "service", "name", "&^", "srvname", -1 }, { "attribute", "name", "=", "attrname", MATCHER_ATTR }, + { "attribute", "name", "!=", "attrname", MATCHER_NOT }, { "attribute", "name", "=~", "attrname", MATCHER_ATTR }, + { "attribute", "name", "!~", "attrname", MATCHER_NOT }, { "attribute", "attr", "=", "attrname", MATCHER_ATTR }, + { "attribute", "attr", "!=", "attrname", MATCHER_NOT }, { "attribute", "attr", "=~", "attrname", MATCHER_ATTR }, + { "attribute", "attr", "!~", "attrname", MATCHER_NOT }, { "attribute", "attr", "&^", "attrname", -1 }, }; -- 2.30.2