Backward compatible XPATH via symbols, not macros

This commit is contained in:
Olof hagsand 2018-07-20 10:51:12 +02:00
parent c71791f168
commit 226c59f25a
10 changed files with 114 additions and 164 deletions

View file

@ -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/<module_name>:<rpc_procedure> 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.

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -56,7 +56,7 @@
#include <cligen/cligen.h>
/* clixon */
#include <clixon/clixon.h>
#include "clixon/clixon.h"
/*
* Turn this on to get a json parse and pretty print test program

View file

@ -54,7 +54,7 @@
#include <cligen/cligen.h>
/* clixon */
#include <clixon/clixon.h>
#include "clixon/clixon.h"
/*
* Turn this on to get a xml parse and pretty print test program

View file

@ -62,7 +62,7 @@ echo "a\n<a><b/></a>" | xpath
#include <cligen/cligen.h>
/* clixon */
#include <clixon/clixon.h>
#include "clixon/clixon.h"
static int
usage(char *argv0)

View file

@ -58,7 +58,7 @@
#include <cligen/cligen.h>
/* clixon */
#include <clixon/clixon.h>
#include "clixon/clixon.h"
/*
*/