Added support for inverted regexps

This commit is contained in:
Olof hagsand 2019-05-29 14:39:36 +02:00
parent 2fe185d683
commit 5706703ab4
9 changed files with 68 additions and 50 deletions

View file

@ -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)

View file

@ -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:
```
<CLICON_YANG_REGEXP>libxml2</CLICON_YANG_REGEXP>
```
## XML
Clixon has its own implementation of XML and XPATH implementation.

View file

@ -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:

View file

@ -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:
```
<CLICON_YANG_REGEXP>libxml2</CLICON_YANG_REGEXP>
```
## I want to program. How do I extend the example?
See [../example/main](../example/main)

View file

@ -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;

View file

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

View file

@ -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,7 +1071,7 @@ yang_find_identity(yang_stmt *ys,
* @retval 0 OK.
*/
static int
resolve_restrictions(yang_stmt *ytype,
yang_type_resolve_restrictions(yang_stmt *ytype,
int *options,
cvec **cvv,
cvec *regexps,
@ -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:

View file

@ -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 '^$'