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 "