diff --git a/CHANGELOG.md b/CHANGELOG.md index 9282b663..2044acdc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,10 @@ ## 4.9.0 Expected: 15 Dec 2020 +### Minor changes + +* Added XPATH functions `position` + ## 4.8.0 18 October 2020 diff --git a/apps/backend/backend_client.c b/apps/backend/backend_client.c index 9645ebd2..f330e2a3 100644 --- a/apps/backend/backend_client.c +++ b/apps/backend/backend_client.c @@ -534,7 +534,7 @@ from_client_get_config(clicon_handle h, } if (ret == 0){ if (netconf_bad_attribute(cbret, "application", - "depth", "Unrecognized value of depth attribute") < 0) + "depth", "Unrecognized value of depth attribute") < 0) goto done; goto ok; } @@ -1044,6 +1044,7 @@ from_client_get(clicon_handle h, int i; cxobj *xerr = NULL; int ret; + char *reason = NULL; clicon_debug(1, "%s", __FUNCTION__); username = clicon_username_get(h); @@ -1074,14 +1075,13 @@ from_client_get(clicon_handle h, content = netconf_content_str2int(attr); /* Clixon extensions: depth */ if ((attr = xml_find_value(xe, "depth")) != NULL){ - char *reason = NULL; if ((ret = parse_int32(attr, &depth, &reason)) < 0){ clicon_err(OE_XML, errno, "parse_int32"); goto done; } if (ret == 0){ if (netconf_bad_attribute(cbret, "application", - "depth", "Unrecognized value of depth attribute") < 0) + "depth", "Unrecognized value of depth attribute") < 0) goto done; goto ok; } @@ -1206,6 +1206,8 @@ from_client_get(clicon_handle h, retval = 0; done: clicon_debug(1, "%s retval:%d", __FUNCTION__, retval); + if (reason) + free(reason); if (xerr) xml_free(xerr); if (xpath) diff --git a/apps/restconf/restconf_methods_get.c b/apps/restconf/restconf_methods_get.c index dbf58e1f..3fccdf74 100644 --- a/apps/restconf/restconf_methods_get.c +++ b/apps/restconf/restconf_methods_get.c @@ -159,7 +159,7 @@ api_data_get2(clicon_handle h, clicon_debug(1, "%s content=%s", __FUNCTION__, attr); if ((int)(content = netconf_content_str2int(attr)) == -1){ if (netconf_bad_attribute_xml(&xerr, "application", - "content", "Unrecognized value of content attribute") < 0) + "content", "Unrecognized value of content attribute") < 0) goto done; if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); @@ -181,7 +181,7 @@ api_data_get2(clicon_handle h, } if (ret==0){ if (netconf_bad_attribute_xml(&xerr, "application", - "depth", "Unrecognized value of depth attribute") < 0) + "depth", "Unrecognized value of depth attribute") < 0) goto done; if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){ clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)"); diff --git a/lib/clixon/clixon_xpath_ctx.h b/lib/clixon/clixon_xpath_ctx.h index eb1929c6..a9a84bf3 100644 --- a/lib/clixon/clixon_xpath_ctx.h +++ b/lib/clixon/clixon_xpath_ctx.h @@ -76,6 +76,7 @@ struct xp_ctx{ enum xp_objtype xc_type; cxobj **xc_nodeset; /* if type XT_NODESET */ int xc_size; /* Length of nodeset */ + int xc_position; int xc_bool; /* if xc_type XT_BOOL */ double xc_number; /* if xc_type XT_NUMBER */ char *xc_string; /* if xc_type XT_STRING */ diff --git a/lib/src/clixon_netconf_lib.c b/lib/src/clixon_netconf_lib.c index 0ab3fef7..3c9b867b 100644 --- a/lib/src/clixon_netconf_lib.c +++ b/lib/src/clixon_netconf_lib.c @@ -274,7 +274,7 @@ netconf_missing_attribute(cbuf *cb, * out of range, pattern mismatch. * @param[out] cb CLIgen buf. Error XML is written in this buffer * @param[in] type Error type: "rpc", "application" or "protocol" - * @param[in] info bad-attribute or bad-element xml + * @param[in] info Attribute name * @param[in] message Error message (will be XML encoded) */ int @@ -303,7 +303,7 @@ netconf_bad_attribute(cbuf *cb, * out of range, pattern mismatch. * @param[out] xret Error XML tree. Free with xml_free after use * @param[in] type Error type: "rpc", "application" or "protocol" - * @param[in] info bad-attribute or bad-element xml + * @param[in] info Attribute name * @param[in] message Error message (will be XML encoded) */ int @@ -331,7 +331,7 @@ netconf_bad_attribute_xml(cxobj **xret, goto done; if (clixon_xml_parse_va(YB_NONE, NULL, &xerr, NULL, "%s" "bad-attribute" - "%s" + "%s" "error", type, info) < 0) goto done; if (message){ @@ -348,7 +348,6 @@ netconf_bad_attribute_xml(cxobj **xret, return retval; } - /*! Create Netconf unknown-attribute error XML tree according to RFC 6241 App A * * An unexpected attribute is present. diff --git a/lib/src/clixon_xpath_eval.c b/lib/src/clixon_xpath_eval.c index f9c8c0a0..5bdac88c 100644 --- a/lib/src/clixon_xpath_eval.c +++ b/lib/src/clixon_xpath_eval.c @@ -494,6 +494,7 @@ xp_eval_predicate(xp_ctx *xc, xcc->xc_type = XT_NODESET; xcc->xc_initial = xc->xc_initial; xcc->xc_node = x; + xcc->xc_position = i; /* For each node in the node-set to be filtered, the PredicateExpr is * evaluated with that node as the context node */ if (cxvec_append(x, &xcc->xc_nodeset, &xcc->xc_size) < 0) @@ -746,12 +747,35 @@ xp_relop(xp_ctx *xc1, xr->xc_bool = (xc1->xc_bool == xc2->xc_bool); break; case XT_NUMBER: - xr->xc_bool = (xc1->xc_number == xc2->xc_number); + switch(op){ + case XO_EQ: + xr->xc_bool = (xc1->xc_number == xc2->xc_number); + break; + case XO_NE: + xr->xc_bool = (xc1->xc_number != xc2->xc_number); + break; + case XO_GE: + xr->xc_bool = (xc1->xc_number >= xc2->xc_number); + break; + case XO_LE: + xr->xc_bool = (xc1->xc_number <= xc2->xc_number); + break; + case XO_LT: + xr->xc_bool = (xc1->xc_number < xc2->xc_number); + break; + case XO_GT: + xr->xc_bool = (xc1->xc_number > xc2->xc_number); + break; + default: + clicon_err(OE_XML, 0, "Operator %s not supported for nodeset/nodeset comparison", clicon_int2str(xpopmap,op)); + goto done; + break; + } break; case XT_STRING: xr->xc_bool = (strcmp(xc1->xc_string, xc2->xc_string)==0); break; - } + } /* switch xc1 */ } else if (xc1->xc_type != XT_NODESET && xc2->xc_type != XT_NODESET){ @@ -991,6 +1015,11 @@ xp_eval(xp_ctx *xc, goto done; goto ok; break; + case XPATHFN_POSITION: + if (xp_function_position(xc, xs->xs_c0, nsc, localonly, xrp) < 0) + goto done; + goto ok; + break; case XPATHFN_COUNT: if (xp_function_count(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 74b02533..43954ece 100644 --- a/lib/src/clixon_xpath_function.c +++ b/lib/src/clixon_xpath_function.c @@ -376,6 +376,41 @@ xp_function_derived_from(xp_ctx *xc, return retval; } +/*! Return a number equal to the context position from the expression evaluation context. + * + * Signature: number position(node-set) + * @param[in] xc0 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 + */ +int +xp_function_position(xp_ctx *xc0, + struct xpath_tree *xs, + cvec *nsc, + int localonly, + xp_ctx **xrp) +{ + int retval = -1; + xp_ctx *xr = NULL; + + if ((xr = malloc(sizeof(*xr))) == NULL){ + clicon_err(OE_UNIX, errno, "malloc"); + goto done; + } + memset(xr, 0, sizeof(*xr)); + xr->xc_initial = xc0->xc_initial; + xr->xc_type = XT_NUMBER; + xr->xc_number = xc0->xc_position; + *xrp = xr; + retval = 0; + done: + return retval; +} + /*! The count function returns the number of nodes in the argument node-set. * * Signature: number count(node-set) @@ -527,7 +562,7 @@ xp_function_contains(xp_ctx *xc, /*! The not function returns true if its argument is false, and false otherwise. * - * Signatire: boolean contains(boolean) + * Signature: boolean not(boolean) */ int xp_function_not(xp_ctx *xc0, diff --git a/lib/src/clixon_xpath_function.h b/lib/src/clixon_xpath_function.h index e0404e74..abadb948 100644 --- a/lib/src/clixon_xpath_function.h +++ b/lib/src/clixon_xpath_function.h @@ -55,7 +55,7 @@ enum clixon_xpath_function{ XPATHFN_ENUM_VALUE, /* RFC 7950 10.5.1 NYI */ XPATHFN_BIT_IS_SET, /* RFC 7950 10.6.1 NYI */ XPATHFN_LAST, /* XPATH 1.0 4.1 NYI */ - XPATHFN_POSITION, /* XPATH 1.0 4.1 NYI */ + XPATHFN_POSITION, /* XPATH 1.0 4.1 */ XPATHFN_COUNT, /* XPATH 1.0 4.1 */ XPATHFN_ID, /* XPATH 1.0 4.1 NYI */ XPATHFN_LOCAL_NAME, /* XPATH 1.0 4.1 NYI */ @@ -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_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); int xp_function_contains(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 1e871e0e..19acd185 100644 --- a/lib/src/clixon_xpath_parse.y +++ b/lib/src/clixon_xpath_parse.y @@ -235,7 +235,6 @@ xp_primary_function(clixon_xpath_yacc *xpy, case XPATHFN_ENUM_VALUE: case XPATHFN_BIT_IS_SET: case XPATHFN_LAST: - case XPATHFN_POSITION: case XPATHFN_ID: case XPATHFN_LOCAL_NAME: case XPATHFN_NAMESPACE_URI: @@ -269,6 +268,7 @@ xp_primary_function(clixon_xpath_yacc *xpy, case XPATHFN_DEREF: case XPATHFN_DERIVED_FROM: case XPATHFN_DERIVED_FROM_OR_SELF: + case XPATHFN_POSITION: case XPATHFN_COUNT: case XPATHFN_NAME: case XPATHFN_CONTAINS: diff --git a/test/mem.sh b/test/mem.sh index 51631574..0e9c972a 100755 --- a/test/mem.sh +++ b/test/mem.sh @@ -103,4 +103,12 @@ for cmd1 in $cmds; do println "Mem test $cmd1 done" done +if [ $err -eq 0 ]; then + echo OK +else + echo -e "\e[31mError" + echo -ne "\e[0m" + exit -1 +fi + unset pattern diff --git a/test/test_openconfig.sh b/test/test_openconfig.sh index 2ef90f55..25815c29 100755 --- a/test/test_openconfig.sh +++ b/test/test_openconfig.sh @@ -98,8 +98,8 @@ done new "Openconfig test: $clixon_cli -1f $cfg -y $f show version ($m modules)" for f in $files; do if [ -n "$(head -1 $f|grep '^module')" ]; then - new "$clixon_cli -1f $cfg -y $f show version" - expectfn "$clixon_cli -1f $cfg -y $f show version" 0 "$version." + new "$clixon_cli -D $DBG -1f $cfg -y $f show version" + expectfn "$clixon_cli -D $DBG -1f $cfg -y $f show version" 0 "$version." fi done diff --git a/test/test_order.sh b/test/test_order.sh index 37b74e9f..65b4d5ae 100755 --- a/test/test_order.sh +++ b/test/test_order.sh @@ -301,7 +301,7 @@ new "add one entry (c) to leaf-list" expecteof "$clixon_netconf -qf $cfg" 0 "c]]>]]>" "^]]>]]>$" new "add one entry (a) to leaf-list first (with no yang namespace - error)" -expecteof "$clixon_netconf -qf $cfg" 0 "a]]>]]>" "^applicationbad-attributeinserterrorUnresolved attribute prefix (no namespace?)]]>]]>$" +expecteof "$clixon_netconf -qf $cfg" 0 "a]]>]]>" "^applicationbad-attributeinserterrorUnresolved attribute prefix (no namespace?)]]>]]>$" new "add one entry (b) to leaf-list first" expecteof "$clixon_netconf -qf $cfg" 0 "b]]>]]>" "^]]>]]>$" @@ -354,7 +354,7 @@ new "add one entry (key c) to list" expecteof "$clixon_netconf -qf $cfg" 0 "cfoo]]>]]>" "^]]>]]>$" new "add one entry (key a) to list first (with no yang namespace - error)" -expecteof "$clixon_netconf -qf $cfg" 0 "afoo]]>]]>" "^applicationbad-attributeinserterrorUnresolved attribute prefix (no namespace?)]]>]]>$" +expecteof "$clixon_netconf -qf $cfg" 0 "afoo]]>]]>" "^applicationbad-attributeinserterrorUnresolved attribute prefix (no namespace?)]]>]]>$" new "add one entry (key b) to list first" expecteof "$clixon_netconf -qf $cfg" 0 "bbar]]>]]>" "^]]>]]>$" diff --git a/test/vagrant/clixon.sh b/test/vagrant/clixon.sh index 59003ad5..d57a3e7e 100755 --- a/test/vagrant/clixon.sh +++ b/test/vagrant/clixon.sh @@ -1,10 +1,6 @@ #!/usr/bin/env bash # Setup cligen and clixon - -set -ux - -#!/usr/bin/env bash -set -eux # x +set -eux if [ $# -ne 3 ]; then echo "usage: $0 "