diff --git a/CHANGELOG.md b/CHANGELOG.md index a95f4535..28c19d6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ # Clixon Changelog ## 3.7.0 (Upcoming) -### Major changes: + +### Major New features * Support for YANG conditionals "must" and "when" according to RFC 7950 Sec 7.5.3 and 7.21.5. * XPATH checked at validation time @@ -10,17 +11,23 @@ * Validation of types and CLI expansion * Example extended with inclusion of iana-if-type RFC 7224 interface identities * Applications which have not strictly enforced the identities may now have problems with validation and may need to be modified. -* Much improved support for XPATH 1.0 according to https://www.w3.org/TR/xpath-10 using yacc/lex - * NOTE: Due to an error in the previous implementation, all XPATH calls on the form `x[a=str]` where `str` is a string (not a number or XML symbol), must be changed to: `x[a='str'] or x[a="str"]` - * This includes all calls to `xpath_vec, xpath_first`, etc. - * All calls to cli_copy_config in CLI spec files must replace 2nd argument from `x[%s=%s]` to `x[%s='%s']` - * The old API can be enabled by setting COMPAT_XSL in include/clixon_custom.h and recompile. + +### API changes on existing features (you may need to change your code) + * Conformance of restconf(RFC-8040) operations where prefix was used instead of module name. * Proper specification for an operation is POST /restconf/operations/: HTTP/1.1 * See https://github.com/clicon/clixon/issues/31, https://github.com/clicon/clixon/pull/32 and https://github.com/clicon/clixon/issues/30 * Thanks David Cornejo and Dmitry Vakhrushev of Netgate for pointing this out. - -### Minor changes: + +* Improved support for XPATH 1.0 according to https://www.w3.org/TR/xpath-10 using yacc/lex + * NOTE: Due to an error in the previous implementation, all XPATH calls on the form `x[a=str]` where `str` is a string (not a number or XML symbol), must be changed to: `x[a='str'] or x[a="str"]` + * This includes all calls to `xpath_vec, xpath_first`, etc. + * All calls to cli_copy_config in CLI spec files must replace 2nd argument from `x[%s=%s]` to `x[%s='%s']` + * xpath_each() is removed + * The old API can be enabled by setting COMPAT_XSL in include/clixon_custom.h and recompile. + +### Minor changes + * Added systemd example files under example/systemd * Changed `plugin_init()` backend return semantics: If returns NULL, _without_ calling clicon_err(), the module is disabled. * Added util subdir, with dedicated standalone xml,json,yang and xpath parser utility test programs. diff --git a/lib/clixon/clixon_xpath.h b/lib/clixon/clixon_xpath.h index 15f241db..086903c8 100644 --- a/lib/clixon/clixon_xpath.h +++ b/lib/clixon/clixon_xpath.h @@ -84,31 +84,20 @@ extern const map_str2int xpopmap[]; * Prototypes */ #if defined(__GNUC__) && __GNUC__ >= 3 -int xpath_vec_nodeset(cxobj *xcur, char *format, cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 2, 5))); -int xpath_vec_nodeset_flag(cxobj *xcur, char *format, uint16_t flags, +int xpath_vec(cxobj *xcur, char *format, cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 2, 5))); +int xpath_vec_flag(cxobj *xcur, char *format, uint16_t flags, cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 2, 6))); -cxobj *xpath_first_nodeset(cxobj *xcur, char *format, ...) __attribute__ ((format (printf, 2, 3))); +cxobj *xpath_first(cxobj *xcur, char *format, ...) __attribute__ ((format (printf, 2, 3))); int xpath_vec_bool(cxobj *xcur, char *format, ...) __attribute__ ((format (printf, 2, 3))); #else -int xpath_vec_nodeset(cxobj *xcur, char *format, cxobj ***vec, size_t *veclen, ...); -int xpath_vec_nodeset_flag(cxobj *xcur, char *format, uint16_t flags, +int xpath_vec(cxobj *xcur, char *format, cxobj ***vec, size_t *veclen, ...); +int xpath_vec_flag(cxobj *xcur, char *format, uint16_t flags, cxobj ***vec, size_t *veclen, ...); -cxobj *xpath_first_nodeset(cxobj *xcur, char *format, ...); +cxobj *xpath_first(cxobj *xcur, char *format, ...); int xpath_vec_bool(cxobj *xcur, char *format, ...); #endif int xpath_vec_ctx(cxobj *xcur, char *xpath, xp_ctx **xrp); -/* backward compatible */ -#ifdef COMPAT_XSL -#define xpath_first(cxtop, format, args...) xpath_first_xsl(cxtop, format, ##args) -#define xpath_vec(cxtop, format, vec, veclen, args...) xpath_vec_xsl(cxtop, format, vec, veclen, ##args) -#define xpath_vec_flag(cxtop, format, flags, vec, veclen, args...) xpath_vec_flag_xsl(cxtop, format, flags, vec, veclen, ##args) -#else -#define xpath_first(cxtop, format, args...) xpath_first_nodeset(cxtop, format, ##args) -#define xpath_vec(cxtop, format, vec, veclen, args...) xpath_vec_nodeset(cxtop, format, vec, veclen, ##args) -#define xpath_vec_flag(cxtop, format, flags, vec, veclen, args...) xpath_vec_nodeset_flag(cxtop, format, flags, vec, veclen, ##args) -#endif - #endif /* _CLIXON_XPATH_H */ diff --git a/lib/clixon/clixon_xsl.h b/lib/clixon/clixon_xsl.h index 2f19623d..5f470fef 100644 --- a/lib/clixon/clixon_xsl.h +++ b/lib/clixon/clixon_xsl.h @@ -39,17 +39,10 @@ /* * Prototypes */ -#if defined(__GNUC__) && __GNUC__ >= 3 -cxobj *xpath_first_xsl(cxobj *cxtop, char *format, ...) __attribute__ ((format (printf, 2, 3))); -int xpath_vec_xsl(cxobj *cxtop, char *format, cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 2, 5))); -int xpath_vec_flag(cxobj *cxtop, char *format, uint16_t flags, - cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 2, 6))); -#else -cxobj *xpath_first_xsl(cxobj *cxtop, char *format, ...); -int xpath_vec_xsl(cxobj *cxtop, char *format, cxobj ***vec, size_t *veclen, ...); +int xpath_vec_xsl(cxobj *cxtop, char *xpath, cxobj ***vec, size_t *veclen); int xpath_vec_flag_xsl(cxobj *cxtop, char *xpath, uint16_t flags, - cxobj ***vec, size_t *veclen, ...); -#endif + cxobj ***vec, size_t *veclen); +cxobj *xpath_first_xsl(cxobj *cxtop, char *xpath); cxobj *xpath_each(cxobj *xn_top, char *xpath, cxobj *prev); diff --git a/lib/src/clixon_xpath.c b/lib/src/clixon_xpath.c index 05fbf56e..7039c6de 100644 --- a/lib/src/clixon_xpath.c +++ b/lib/src/clixon_xpath.c @@ -62,6 +62,7 @@ #include "clixon_handle.h" #include "clixon_yang.h" #include "clixon_xml.h" +#include "clixon_xsl.h" #include "clixon_xpath_parse.h" #include "clixon_xpath_ctx.h" #include "clixon_xpath.h" @@ -1091,10 +1092,27 @@ xpath_vec_ctx(cxobj *xcur, return retval; } +/*! Xpath nodeset function where only the first matching entry is returned + * args: + * @param[in] xcur xml-tree where to search + * @param[in] xpath string with XPATH syntax + * @retval xml-tree of first match + * @retval NULL Error or not found + * + * @code + * cxobj *x; + * if ((x = xpath_first(xtop, "//symbol/foo")) != NULL) { + * ... + * } + * @endcode + * @note the returned pointer points into the original tree so should not be freed fter use. + * @note return value does not see difference between error and not found + * @see also xpath_vec. + */ cxobj * -xpath_first_nodeset(cxobj *xcur, - char *format, - ...) +xpath_first(cxobj *xcur, + char *format, + ...) { cxobj *cx = NULL; va_list ap; @@ -1118,10 +1136,16 @@ xpath_first_nodeset(cxobj *xcur, goto done; } va_end(ap); +#ifdef COMPAT_XSL + if ((cx = xpath_first_xsl(xcur, xpath)) == NULL) + goto done; +#else if (xpath_vec_ctx(xcur, xpath, &xr) < 0) goto done; + if (xr && xr->xc_type == XT_NODESET && xr->xc_size) cx = xr->xc_nodeset[0]; +#endif done: if (xr) ctx_free(xr); @@ -1140,11 +1164,11 @@ xpath_first_nodeset(cxobj *xcur, * @retval -1 Error */ int -xpath_vec_nodeset(cxobj *xcur, - char *format, - cxobj ***vec, - size_t *veclen, - ...) +xpath_vec(cxobj *xcur, + char *format, + cxobj ***vec, + size_t *veclen, + ...) { int retval = -1; va_list ap; @@ -1168,6 +1192,10 @@ xpath_vec_nodeset(cxobj *xcur, goto done; } va_end(ap); +#ifdef COMPAT_XSL + if (xpath_vec_xsl(xcur, xpath, vec, veclen) < 0) + goto done; +#else if (xpath_vec_ctx(xcur, xpath, &xr) < 0) goto done; if (xr && xr->xc_type == XT_NODESET){ @@ -1175,6 +1203,7 @@ xpath_vec_nodeset(cxobj *xcur, xr->xc_nodeset = NULL; *veclen = xr->xc_size; } +#endif retval = 0; done: if (xr) @@ -1184,7 +1213,7 @@ xpath_vec_nodeset(cxobj *xcur, return retval; } -/* A restricted xpath that returns a vector of matches (only nodes marked with flags) +/* Xpath that returns a vector of matches (only nodes marked with flags) * @param[in] xcur xml-tree where to search * @param[in] xpath string with XPATH syntax * @param[in] flags Set of flags that return nodes must match (0 if all) @@ -1208,20 +1237,22 @@ xpath_vec_nodeset(cxobj *xcur, * @see also xpath_vec This is a specialized version. */ int -xpath_vec_nodeset_flag(cxobj *xcur, - char *format, - uint16_t flags, - cxobj ***vec, - size_t *veclen, - ...) +xpath_vec_flag(cxobj *xcur, + char *format, + uint16_t flags, + cxobj ***vec, + size_t *veclen, + ...) { int retval = -1; va_list ap; size_t len; char *xpath = NULL; xp_ctx *xr = NULL; +#ifndef COMPAT_XSL int i; cxobj *x; +#endif va_start(ap, veclen); len = vsnprintf(NULL, 0, format, ap); @@ -1239,6 +1270,10 @@ xpath_vec_nodeset_flag(cxobj *xcur, goto done; } va_end(ap); +#ifdef COMPAT_XSL + if (xpath_vec_flag_xsl(xcur, xpath, flags, vec, veclen) < 0) + goto done; +#else if (xpath_vec_ctx(xcur, xpath, &xr) < 0) goto done; @@ -1250,6 +1285,8 @@ xpath_vec_nodeset_flag(cxobj *xcur, goto done; } } +#endif + retval = 0; done: if (xr) diff --git a/lib/src/clixon_xsl.c b/lib/src/clixon_xsl.c index 8f34a0a1..873b8532 100644 --- a/lib/src/clixon_xsl.c +++ b/lib/src/clixon_xsl.c @@ -859,11 +859,26 @@ xpath_choice(cxobj *xcur, return retval; } -/*! Help function to xpath_first +/*! Xpath nodeset function where only the first matching entry is returned + * args: + * @param[in] xcur xml-tree where to search + * @param[in] xpath string with XPATH syntax + * @retval xml-tree of first match + * @retval NULL Error or not found + * + * @code + * cxobj *x; + * if ((x = xpath_first(xtop, "//symbol/foo")) != NULL) { + * ... + * } + * @endcode + * @note the returned pointer points into the original tree so should not be freed fter use. + * @note return value does not see difference between error and not found + * @see xpath_first. This is obsolete and only enabled with COMPAT_XSL */ -static cxobj * -xpath_first0(cxobj *xcur, - char *xpath) +cxobj * +xpath_first_xsl(cxobj *xcur, + char *xpath) { cxobj **vec1 = NULL; size_t vec1len = 0; @@ -881,57 +896,6 @@ xpath_first0(cxobj *xcur, return xn; } -/*! A restricted xpath function where the first matching entry is returned - * See xpath1() on details for subset. - * args: - * @param[in] xcur xml-tree where to search - * @param[in] xpath string with XPATH syntax - * @retval xml-tree of first match - * @retval NULL Error or not found - * - * @code - * cxobj *x; - * if ((x = xpath_first(xtop, "//symbol/foo")) != NULL) { - * ... - * } - * @endcode - * @note the returned pointer points into the original tree so should not be freed after use. - * @note return value does not see difference between error and not found - * @see also xpath_vec. - */ -cxobj * -xpath_first_xsl(cxobj *xcur, - char *format, - ...) -{ - cxobj *retval = NULL; - va_list ap; - size_t len; - char *xpath; - - va_start(ap, format); - len = vsnprintf(NULL, 0, format, ap); - va_end(ap); - /* allocate a message string exactly fitting the message length */ - if ((xpath = malloc(len+1)) == NULL){ - clicon_err(OE_UNIX, errno, "malloc"); - goto done; - } - /* second round: compute write message from reason and args */ - va_start(ap, format); - if (vsnprintf(xpath, len+1, format, ap) < 0){ - clicon_err(OE_UNIX, errno, "vsnprintf"); - va_end(ap); - goto done; - } - va_end(ap); - retval = xpath_first0(xcur, xpath); - done: - if (xpath) - free(xpath); - return retval; -} - /*! A restricted xpath iterator that loops over all matching entries. Dont use. * * See xpath1() on details for subset. @@ -949,8 +913,7 @@ xpath_first_xsl(cxobj *xcur, * * @note The returned pointer points into the original tree so should not be freed * after use. - * @see also xpath, xpath_vec. - * @note uses a static variable: consider replacing with xpath_vec() instead + * @note obsolete. Dont use */ cxobj * xpath_each(cxobj *xcur, @@ -1014,41 +977,22 @@ xpath_each(cxobj *xcur, * @note Although the returned vector must be freed after use, * the returned xml trees should not. * @see also xpath_first, xpath_each. + * @see xpath_vec. This is obsolete and only enabled with COMPAT_XSL */ int xpath_vec_xsl(cxobj *xcur, - char *format, - cxobj ***vec, - size_t *veclen, - ...) + char *xpath, + cxobj ***vec, + size_t *veclen) { int retval = -1; - va_list ap; - size_t len; - char *xpath = NULL; - va_start(ap, veclen); - len = vsnprintf(NULL, 0, format, ap); - va_end(ap); - /* allocate a message string exactly fitting the message length */ - if ((xpath = malloc(len+1)) == NULL){ - clicon_err(OE_UNIX, errno, "malloc"); - goto done; - } - /* second round: compute write message from reason and args */ - va_start(ap, veclen); - if (vsnprintf(xpath, len+1, format, ap) < 0){ - clicon_err(OE_UNIX, errno, "vsnprintf"); - va_end(ap); - goto done; - } - va_end(ap); *vec = NULL; *veclen = 0; - retval = xpath_choice(xcur, xpath, 0x0, vec, veclen); + if (xpath_choice(xcur, xpath, 0x0, vec, veclen) < 0) + goto done; + retval = 0; done: - if (xpath) - free(xpath); return retval; } @@ -1073,43 +1017,23 @@ xpath_vec_xsl(cxobj *xcur, * @endcode * @Note that although the returned vector must be freed after use, the returned xml * trees need not be. - * @see also xpath_vec This is a specialized version. + * @see xpath_vec_flag. This is obsolete and only enabled with COMPAT_XSL */ int xpath_vec_flag_xsl(cxobj *xcur, - char *format, + char *xpath, uint16_t flags, cxobj ***vec, - size_t *veclen, - ...) + size_t *veclen) { int retval = -1; - va_list ap; - size_t len; - char *xpath; - va_start(ap, veclen); - len = vsnprintf(NULL, 0, format, ap); - va_end(ap); - /* allocate a message string exactly fitting the message length */ - if ((xpath = malloc(len+1)) == NULL){ - clicon_err(OE_UNIX, errno, "malloc"); - goto done; - } - /* second round: compute write message from reason and args */ - va_start(ap, veclen); - if (vsnprintf(xpath, len+1, format, ap) < 0){ - clicon_err(OE_UNIX, errno, "vsnprintf"); - va_end(ap); - goto done; - } - va_end(ap); *vec=NULL; *veclen = 0; - retval = xpath_choice(xcur, xpath, flags, vec, veclen); + if (xpath_choice(xcur, xpath, flags, vec, veclen) < 0) + goto done; + retval = 0; done: - if (xpath) - free(xpath); return retval; } diff --git a/util/Makefile.in b/util/Makefile.in index 24379f48..a17db716 100644 --- a/util/Makefile.in +++ b/util/Makefile.in @@ -61,7 +61,7 @@ LIBS = @LIBS@ CPPFLAGS = @CPPFLAGS@ -INCLUDES = -I. @INCLUDES@ -I$(top_srcdir)/lib/clixon -I$(top_srcdir)/include -I$(top_srcdir) +INCLUDES = -I. @INCLUDES@ -I$(top_srcdir)/lib -I$(top_srcdir)/include -I$(top_srcdir) MYLIB = ../lib/src/libclixon$(SH_SUFFIX).$(CLIXON_MAJOR).$(CLIXON_MINOR) diff --git a/util/clixon_util_json.c b/util/clixon_util_json.c index 8cffdf3a..dd16e0e0 100644 --- a/util/clixon_util_json.c +++ b/util/clixon_util_json.c @@ -56,7 +56,7 @@ #include /* clixon */ -#include +#include "clixon/clixon.h" /* * Turn this on to get a json parse and pretty print test program diff --git a/util/clixon_util_xml.c b/util/clixon_util_xml.c index ee32a9bb..72730000 100644 --- a/util/clixon_util_xml.c +++ b/util/clixon_util_xml.c @@ -54,7 +54,7 @@ #include /* clixon */ -#include +#include "clixon/clixon.h" /* * Turn this on to get a xml parse and pretty print test program diff --git a/util/clixon_util_xpath.c b/util/clixon_util_xpath.c index 7bc849de..5daccb14 100644 --- a/util/clixon_util_xpath.c +++ b/util/clixon_util_xpath.c @@ -62,7 +62,7 @@ echo "a\n" | xpath #include /* clixon */ -#include +#include "clixon/clixon.h" static int usage(char *argv0) diff --git a/util/clixon_util_yang.c b/util/clixon_util_yang.c index 1526ae62..22847b0d 100644 --- a/util/clixon_util_yang.c +++ b/util/clixon_util_yang.c @@ -58,7 +58,7 @@ #include /* clixon */ -#include +#include "clixon/clixon.h" /* */