From 5706703ab40ffbddc2abacb88b32f1e8cd4a9014 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Wed, 29 May 2019 14:39:36 +0200 Subject: [PATCH] Added support for inverted regexps --- CHANGELOG.md | 3 ++- README.md | 18 +++++++++++++++- apps/cli/cli_generate.c | 17 +++++++++++---- doc/FAQ.md | 21 ------------------- lib/src/clixon_yang.c | 2 -- lib/src/clixon_yang_internal.h | 8 ++++--- lib/src/clixon_yang_type.c | 38 ++++++++++++++++++++++------------ test/test_pattern.sh | 7 ++++--- util/clixon_util_regexp.c | 4 ++-- 9 files changed, 68 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 723c870d..b80ee968 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,11 @@ # Clixon Changelog -## 3.10.0/4.0.0 (Upcoming) +## 4.0.0 (Upcoming) ### Major New features * Regexp improvements: Libxml2 XSD, multiple patterns, optimization * Support for multiple patterns as described in RFC7950 Section 9.4.7 + * Support for inverted patterns as described in RFC7950 Section 9.4.6 * Libxml2 support for full XSD matching as alternative to Posix translation * Configure with: `./configure --with-libxml2` * Set `CLICON_YANG_REGEXP` to libxml2 (default is posix) diff --git a/README.md b/README.md index c97cb4ef..c5509c03 100644 --- a/README.md +++ b/README.md @@ -115,11 +115,27 @@ However, the following YANG syntax modules are not implemented (reference to RFC - refine (7.13.2) - status (7.21.2) - extension (7.19) -- modifier (9.4.6) - YIN (13) - Yang extended Xpath functions: re-match(), deref)(), derived-from(), derived-from-or-self(), enum-value(), bit-is-set() (10.2-10.6) - Default values on leaf-lists are not supported (7.7.2) +### Yang patterns +Yang type patterns use regexps defined in [W3C XML XSD](http://www.w3.org/TR/2004/REC-xmlschema-2-20041028). XSD regexp:s are +slightly different from POSIX regexp. + +Clixon supports two regular expressions engines: + * "Posix" which is the default method, which _translates_ XSD regexp:s to posix before matching with the standard Linux regex engine. This translation is not complete but can be considered "good-enough" for most yang use-cases. For reference, all standard Yang models in [https://github.com/YangModels/yang] have been tested. + * "Libxml2" which uses the XSD regex engine in Libxml2. This is a complete XSD engine but you need to compile and link with libxml2 which may add overhead. + +To use libxml2 in clixon you need enable libxml2 in both cligen and clixon: +``` +> ./configure --with-libxml2 # both cligen and clixon +``` +You then need to set the following configure option: +``` + libxml2 +``` + ## XML Clixon has its own implementation of XML and XPATH implementation. diff --git a/apps/cli/cli_generate.c b/apps/cli/cli_generate.c index a78d55f1..69b360ae 100644 --- a/apps/cli/cli_generate.c +++ b/apps/cli/cli_generate.c @@ -287,21 +287,30 @@ yang2cli_var_pattern(clicon_handle h, char *mode; cg_var *cvp; char *pattern; + int invert; + char *posix; mode = clicon_yang_regexp(h); cvp = NULL; /* Loop over compiled regexps */ while ((cvp = cvec_each(patterns, cvp)) != NULL){ pattern = cv_string_get(cvp); + invert = cv_flag(cvp, V_INVERT); if (strcmp(mode, "posix") == 0){ - char *posix = NULL; + posix = NULL; if (regexp_xsd2posix(pattern, &posix) < 0) goto done; - cprintf(cb, " regexp:\"%s\"", posix); - if (posix) + cprintf(cb, " regexp:%s\"%s\"", + invert?"!":"", + posix); + if (posix){ free(posix); + posix = NULL; + } } else - cprintf(cb, " regexp:\"%s\"", pattern); + cprintf(cb, " regexp:%s\"%s\"", + invert?"!":"", + pattern); } retval = 0; done: diff --git a/doc/FAQ.md b/doc/FAQ.md index fc71e607..c052e9ae 100644 --- a/doc/FAQ.md +++ b/doc/FAQ.md @@ -27,7 +27,6 @@ * [How should I start the backend daemon?](#how-should-i-start-the-backend-daemon) * [Can I use systemd with Clixon?](#can-i-use-systemd-with-clixon) * [How can I add extra XML?](#how-can-i-add-extra-xml) - * [What about Regexps?](#what-about-regexps) * [I want to program. How do I extend the example?](#i-want-to-program-how-do-i-extend-the-example) * [How is a plugin initiated?](#how-is-a-plugin-initiated) * [How do I write a commit function?](#how-do-i-write-a-commit-function) @@ -439,26 +438,6 @@ You add this via the -c option: The second way is by programming the plugin_reset() in the backend plugin. The example code contains an example on how to do this (see plugin_reset() in example_backend.c). -## What about Regexps? - -Yang type patterns use regexps defined in [W3C XML XSD -](http://www.w3.org/TR/2004/REC-xmlschema-2-20041028). XSD regexp:s are -slightly different from POSIX regexp. - -lixon supports two regular expressions engines: -* "Posix" which is the default method, _translates_ XSD regexp:s to posix before matching with the standard Linux regex engine. This translation is not complete but considered -"good-enough" for most yang use-cases. For reference, all standard -Yang models in [https://github.com/YangModels/yang] have been tested. -* "Libxml2" which uses the XSD regex engine in Libxml2. This is a complete XSD engine but you need to compile and link with libxml2 which may add overhead. - -To use libxml2 in clixon you need enable libxml2 in both cligen and clixon: -``` -> ./configure --with-libxml2 # both cligen and clixon -``` -You then need to set the following configure option: -``` - libxml2 -``` ## I want to program. How do I extend the example? See [../example/main](../example/main) diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index 144990da..cd47c102 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -1368,8 +1368,6 @@ ys_populate_leaf(clicon_handle h, if (yparent && yparent->ys_keyword == Y_LIST){ if ((ret = yang_key_match(yparent, ys->ys_argument)) < 0) goto done; - if (ret == 1) - cv_flag_set(cv, V_UNIQUE); } ys->ys_cv = cv; retval = 0; diff --git a/lib/src/clixon_yang_internal.h b/lib/src/clixon_yang_internal.h index f36692ff..acf7d416 100644 --- a/lib/src/clixon_yang_internal.h +++ b/lib/src/clixon_yang_internal.h @@ -41,10 +41,12 @@ /* - * Actually cligen variable stuff XXX + * Clixon-specific cligen variable (cv) flags + * CLIgen flags defined are in the range 0x01 -0x0f + * An application can use any flags above that + * @see cv_flag */ -#define V_UNIQUE 0x01 /* Variable flag */ -#define V_UNSET 0x08 /* Variable is unset, ie no default */ +#define V_UNSET 0x10 /* Used by XML code to denote a value is not default */ #define YANG_FLAG_MARK 0x01 /* Marker for dynamic algorithms, eg expand */ diff --git a/lib/src/clixon_yang_type.c b/lib/src/clixon_yang_type.c index 34b1cf2a..702093d0 100644 --- a/lib/src/clixon_yang_type.c +++ b/lib/src/clixon_yang_type.c @@ -33,8 +33,9 @@ * Yang type related functions * Part of this is type resolving which is pretty complex - * - * (called at parse / set cache) + * +--> yang_type_cache_set + * +--> compile_pattern2regexp + * (called at parse) | * ys_resolve_type --+ ys_populate_range, yang_enum_int_value(NULL) * \ | cml * v v v @@ -43,9 +44,10 @@ * ^ ^ ^ ^ * | | | | * | yang2cli_var | yang2cli_var_union_one - * ys_cv_validate ys_cv_validate_union_one - * | - * ys_populate_leaf, xml_cv_cache (NULL) + * ys_cv_validate----+ ys_cv_validate_union_one + * | \ / + * ys_populate_leaf, +--> cv_validate1 --> cv_validate_pattern (exec regexps) + * xml_cv_cache (NULL) */ #ifdef HAVE_CONFIG_H @@ -278,13 +280,15 @@ yang_type_cache_free(yang_type_cache *ycache) return 0; } -/* Compile yang patterns in string form to regex compiled void* form +/*! Compile yang patterns in string form to regex compiled void* form * and re-store into "patterns" cvec. * This is done here instead of deep in resolve code (resolve_restrictions) * since it id dependent on clicon_handle. * The downside is that all accesses to "patterns" must pass via the cache. * If calls to yang_type_resolve is made without the cache is set, will be * wrong. + * @see match_regexp in cligen code + * @see yang_type_resolve_restrictions where patterns is set */ static int compile_pattern2regexp(clicon_handle h, @@ -317,6 +321,9 @@ compile_pattern2regexp(clicon_handle h, goto done; } cv_void_set(rcv, re); + /* invert pattern check */ + if (cv_flag(pcv, V_INVERT)) + cv_flag_set(rcv, V_INVERT); } retval = 1; done: @@ -515,6 +522,8 @@ cv_validate_pattern(clicon_handle h, re = cv_void_get(cvr); if ((ret = regex_exec(h, re, str?str:"")) < 0) goto done; + if (cv_flag(cvr, V_INVERT)) + ret = !ret; /* swap 0 and 1 */ if (ret == 0){ if (reason) *reason = cligen_reason("regexp match fail: pattern does not match %s", @@ -1062,11 +1071,11 @@ yang_find_identity(yang_stmt *ys, * @retval 0 OK. */ static int -resolve_restrictions(yang_stmt *ytype, - int *options, - cvec **cvv, - cvec *regexps, - uint8_t *fraction) +yang_type_resolve_restrictions(yang_stmt *ytype, + int *options, + cvec **cvv, + cvec *regexps, + uint8_t *fraction) { int retval = -1; yang_stmt *ys; @@ -1094,6 +1103,9 @@ resolve_restrictions(yang_stmt *ytype, goto done; } pattern = ys->ys_argument; /* clear text pattern */ + /* Check 1.1 invert pattern */ + if (yang_find(ys, Y_MODIFIER, "invert-match") != NULL) + cv_flag_set(cv, V_INVERT); cv_string_set(cv, pattern); } } @@ -1165,7 +1177,7 @@ yang_type_resolve(yang_stmt *yorig, /* Check if type is basic type. If so, return that */ if ((prefix == NULL && yang_builtin(type))){ *yrestype = ytype; - if (resolve_restrictions(ytype, options, cvv, patterns, fraction) < 0) + if (yang_type_resolve_restrictions(ytype, options, cvv, patterns, fraction) < 0) goto done; goto ok; } @@ -1210,7 +1222,7 @@ yang_type_resolve(yang_stmt *yorig, fraction) < 0) goto done; /* appends patterns, overwrites others if any */ - if (resolve_restrictions(ytype, options, cvv, patterns, fraction) < 0) + if (yang_type_resolve_restrictions(ytype, options, cvv, patterns, fraction) < 0) goto done; } ok: diff --git a/test/test_pattern.sh b/test/test_pattern.sh index d546c667..36322a35 100755 --- a/test/test_pattern.sh +++ b/test/test_pattern.sh @@ -64,11 +64,9 @@ module pattern{ type string { length "1..max"; pattern '[a-zA-Z_][a-zA-Z0-9\-_.]*'; -/* pattern '[xX][mM][lL].*' { modifier invert-match; } -*/ } } typedef twomatchtype { @@ -409,7 +407,7 @@ testrun rfc2 0 'xx00' new "Test for RFC7950 Sec 9.4.7 pattern example 3 (invert match)" testrun rfc3 1 'enabled' testrun rfc3 0 '10-mbit' -#testrun rfc3 0 'xml-element' # invert-match dont work +testrun rfc3 0 'xml-element' # invert: dont match xml new "Test for two patterns" testrun 'twomatch' 1 'gksdhfsakjhdksa' @@ -717,6 +715,9 @@ expectfn "$clixon_cli -1f $cfg -l o set c rfc3 enabled" 0 '^$' new "CLI tests for RFC7950 Sec 9.4.7 ex 3 10-mbit (should fail)" expectfn "$clixon_cli -1f $cfg -l o set c rfc3 10-mbit" 255 '^CLI syntax error:' +new "CLI tests for RFC7950 Sec 9.4.7 ex 3 xml-element (should fail)" +expectfn "$clixon_cli -1f $cfg -l o set c rfc3 xml-element" 255 '^CLI syntax error:' + new "CLI tests for two patterns gksdhfsakjhdks" expectfn "$clixon_cli -1f $cfg -l o set c twomatch gksdhfsakjhdks" 0 '^$' diff --git a/util/clixon_util_regexp.c b/util/clixon_util_regexp.c index 1687a32d..d0990ef7 100644 --- a/util/clixon_util_regexp.c +++ b/util/clixon_util_regexp.c @@ -96,8 +96,8 @@ regex_posix(char *regexp, int nr, int debug) { - int retval = -1; - char *posix = NULL; + int retval = -1; + char *posix = NULL; char pattern[1024]; int status = 0; regex_t re;