diff --git a/lib/src/clixon_xpath_eval.c b/lib/src/clixon_xpath_eval.c index a5682cda3..b18046ef7 100644 --- a/lib/src/clixon_xpath_eval.c +++ b/lib/src/clixon_xpath_eval.c @@ -1045,6 +1045,11 @@ xp_eval(xp_ctx *xc, goto done; goto ok; break; + case XPATHFN_BIT_IS_SET: + if (xp_function_bit_is_set(xc, xs->xs_c0, nsc, localonly, xrp) < 0) + goto done; + goto ok; + break; case XPATHFN_POSITION: if (xp_function_position(xc, xs->xs_c0, nsc, localonly, xrp) < 0) goto done; diff --git a/lib/src/clixon_xpath_function.c b/lib/src/clixon_xpath_function.c index f930413da..17dd7f367 100644 --- a/lib/src/clixon_xpath_function.c +++ b/lib/src/clixon_xpath_function.c @@ -379,6 +379,80 @@ xp_function_derived_from(xp_ctx *xc, return retval; } +/*! Returns true if the first node value has a bit set + * + * The bit-is-set() function returns "true" if the first node in + * document order in the argument "nodes" is a node of type "bits" and + * its value has the bit "bit-name" set; otherwise, it returns "false". + * + * Signature: boolean bit-is-set(node-set nodes, string bit-name) + + * @param[in] xc Incoming context + * @param[in] xs XPATH node tree + * @param[in] nsc XML Namespace context + * @param[in] localonly Skip prefix and namespace tests (non-standard) + * @param[out] xrp Resulting context + * @retval 0 OK + * @retval -1 Error + * Example: interface[bit-is-set(flags, 'UP') + * @see RFC 7950 Sec 10.6 + * typecheck is not made but assume this is done by validate + * XXX: lacks proper parsing of bits, just use strstr, see eg cv_validate1 + */ +int +xp_function_bit_is_set(xp_ctx *xc, + struct xpath_tree *xs, + cvec *nsc, + int localonly, + xp_ctx **xrp) +{ + int retval = -1; + xp_ctx *xr = NULL; + xp_ctx *xr0 = NULL; + xp_ctx *xr1 = NULL; + char *s1 = NULL; + cxobj *x; + char *body; + + if (xs == NULL || xs->xs_c0 == NULL || xs->xs_c1 == NULL){ + clicon_err(OE_XML, EINVAL, "contains expects but did not get two arguments"); + goto done; + } + /* First node-set argument */ + if (xp_eval(xc, xs->xs_c0, nsc, localonly, &xr0) < 0) + goto done; + /* Second string argument */ + if (xp_eval(xc, xs->xs_c1, nsc, localonly, &xr1) < 0) + goto done; + if (ctx2string(xr1, &s1) < 0) + goto done; + if ((xr = malloc(sizeof(*xr))) == NULL){ + clicon_err(OE_UNIX, errno, "malloc"); + goto done; + } + memset(xr, 0, sizeof(*xr)); + xr->xc_type = XT_BOOL; + /* The first node in document order in the argument "nodes" + * is a node of type "bits") and # NOT IMPLEMENTED + * its value has the bit "bit-name" set + */ + if (xr0->xc_size && + (x = xr0->xc_nodeset[0]) != NULL && + (body = xml_body(x)) != NULL){ + xr->xc_bool = strstr(body, s1) != NULL; + } + *xrp = xr; + retval = 0; + done: + if (xr0) + ctx_free(xr0); + if (xr1) + ctx_free(xr1); + if (s1) + free(s1); + return retval; +} + /*! Return a number equal to the context position from the expression evaluation context. * * Signature: number position(node-set) diff --git a/lib/src/clixon_xpath_function.h b/lib/src/clixon_xpath_function.h index a8f377bdc..50f798ea9 100644 --- a/lib/src/clixon_xpath_function.h +++ b/lib/src/clixon_xpath_function.h @@ -53,7 +53,7 @@ enum clixon_xpath_function{ XPATHFN_DERIVED_FROM, /* RFC 7950 10.4.1 */ XPATHFN_DERIVED_FROM_OR_SELF, /* RFC 7950 10.4.2 */ XPATHFN_ENUM_VALUE, /* RFC 7950 10.5.1 NYI */ - XPATHFN_BIT_IS_SET, /* RFC 7950 10.6.1 NYI */ + XPATHFN_BIT_IS_SET, /* RFC 7950 10.6.1 */ XPATHFN_LAST, /* XPATH 1.0 4.1 NYI */ XPATHFN_POSITION, /* XPATH 1.0 4.1 */ XPATHFN_COUNT, /* XPATH 1.0 4.1 */ @@ -96,6 +96,7 @@ const char *xp_fnname_int2str(enum clixon_xpath_function code); int xp_function_current(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp); int xp_function_deref(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp); int xp_function_derived_from(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, int self, xp_ctx **xrp); +int xp_function_bit_is_set(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp); int xp_function_position(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp); int xp_function_count(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp); int xp_function_name(xp_ctx *xc, struct xpath_tree *xs, cvec *nsc, int localonly, xp_ctx **xrp); diff --git a/lib/src/clixon_xpath_parse.y b/lib/src/clixon_xpath_parse.y index 55f3d1197..641105139 100644 --- a/lib/src/clixon_xpath_parse.y +++ b/lib/src/clixon_xpath_parse.y @@ -247,7 +247,6 @@ xp_primary_function(clixon_xpath_yacc *xpy, switch (fn){ case XPATHFN_RE_MATCH: /* Group of NOT IMPLEMENTED xpath functions */ case XPATHFN_ENUM_VALUE: - case XPATHFN_BIT_IS_SET: case XPATHFN_LAST: case XPATHFN_ID: case XPATHFN_LOCAL_NAME: @@ -279,6 +278,7 @@ xp_primary_function(clixon_xpath_yacc *xpy, case XPATHFN_CURRENT: /* Group of implemented xpath functions */ case XPATHFN_DEREF: case XPATHFN_DERIVED_FROM: + case XPATHFN_BIT_IS_SET: case XPATHFN_DERIVED_FROM_OR_SELF: case XPATHFN_POSITION: case XPATHFN_COUNT: diff --git a/test/test_xpath_functions.sh b/test/test_xpath_functions.sh index 3b2cfbeee..79bb67cb5 100755 --- a/test/test_xpath_functions.sh +++ b/test/test_xpath_functions.sh @@ -82,6 +82,14 @@ module $APPNAME{ base interface-type; } } + leaf flags { + description "See RFC 7950 Sec 10.6.1"; + type bits{ + bit UP; + bit PROMISCUOUS; + bit DISABLED; + } + } } augment "/ex:interface" { when 'derived-from(type, "ex:ethernet")'; @@ -173,6 +181,13 @@ expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO< new "netconf discard-changes" expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^]]>]]>$" +# bit-is-set +new "Add interfaces with different flags" +expecteof "$clixon_netconf -qf $cfg -D $DBG" 0 "$DEFAULTHELLOe0UPe1UP PROMISCUOUSe2PROMISCUOUS]]>]]>" "^]]>]]>" + +new "netconf bit-is-set" +expecteof "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO]]>]]>" "^e1UP PROMISCUOUSe2PROMISCUOUS]]>]]>$" + if [ $BE -ne 0 ]; then new "Kill backend" # Check if premature kill