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;