datastore text works with replace
This commit is contained in:
parent
ee9b74d735
commit
d02015f456
15 changed files with 627 additions and 160 deletions
|
|
@ -47,6 +47,8 @@
|
|||
#include <regex.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <cligen/cligen.h>
|
||||
|
||||
/* clicon */
|
||||
#include "clixon_queue.h"
|
||||
#include "clixon_string.h"
|
||||
|
|
@ -241,6 +243,97 @@ percent_decode(char *esc,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Split a string into a cligen variable vector using 1st and 2nd delimiter
|
||||
* Split a string first into elements delimited by delim1, then into
|
||||
* pairs delimited by delim2.
|
||||
* @param[in] string String to split
|
||||
* @param[in] delim1 First delimiter char that delimits between elements
|
||||
* @param[in] delim2 Second delimiter char for pairs within an element
|
||||
* @param[out] cvp Created cligen variable vector, deallocate w cvec_free
|
||||
* @retval 0 on OK
|
||||
* @retval -1 error
|
||||
*
|
||||
* @example,
|
||||
* Assuming delim1 = '&' and delim2 = '='
|
||||
* a=b&c=d -> [[a,"b"][c="d"]
|
||||
* kalle&c=d -> [[c="d"]] # Discard elements with no delim2
|
||||
* XXX differentiate between error and null cvec.
|
||||
*/
|
||||
int
|
||||
str2cvec(char *string,
|
||||
char delim1,
|
||||
char delim2,
|
||||
cvec **cvp)
|
||||
{
|
||||
int retval = -1;
|
||||
char *s;
|
||||
char *s0 = NULL;;
|
||||
char *val; /* value */
|
||||
char *valu; /* unescaped value */
|
||||
char *snext; /* next element in string */
|
||||
cvec *cvv = NULL;
|
||||
cg_var *cv;
|
||||
|
||||
if ((s0 = strdup(string)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto err;
|
||||
}
|
||||
s = s0;
|
||||
if ((cvv = cvec_new(0)) ==NULL){
|
||||
clicon_err(OE_UNIX, errno, "cvec_new");
|
||||
goto err;
|
||||
}
|
||||
while (s != NULL) {
|
||||
/*
|
||||
* In the pointer algorithm below:
|
||||
* name1=val1; name2=val2;
|
||||
* ^ ^ ^
|
||||
* | | |
|
||||
* s val snext
|
||||
*/
|
||||
if ((snext = index(s, delim1)) != NULL)
|
||||
*(snext++) = '\0';
|
||||
if ((val = index(s, delim2)) != NULL){
|
||||
*(val++) = '\0';
|
||||
if (percent_decode(val, &valu) < 0)
|
||||
goto err;
|
||||
if ((cv = cvec_add(cvv, CGV_STRING)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cvec_add");
|
||||
goto err;
|
||||
}
|
||||
while ((strlen(s) > 0) && isblank(*s))
|
||||
s++;
|
||||
cv_name_set(cv, s);
|
||||
cv_string_set(cv, valu);
|
||||
free(valu); valu = NULL;
|
||||
}
|
||||
else{
|
||||
if (strlen(s)){
|
||||
if ((cv = cvec_add(cvv, CGV_STRING)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cvec_add");
|
||||
goto err;
|
||||
}
|
||||
cv_name_set(cv, s);
|
||||
cv_string_set(cv, "");
|
||||
}
|
||||
}
|
||||
s = snext;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
*cvp = cvv;
|
||||
if (s0)
|
||||
free(s0);
|
||||
return retval;
|
||||
err:
|
||||
if (cvv){
|
||||
cvec_free(cvv);
|
||||
cvv = NULL;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
/*! strndup() for systems without it, such as xBSD
|
||||
*/
|
||||
#ifndef HAVE_STRNDUP
|
||||
|
|
@ -265,6 +358,8 @@ clicon_strndup (const char *str,
|
|||
}
|
||||
#endif /* ! HAVE_STRNDUP */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Turn this on for uni-test programs
|
||||
* Usage: clixon_string join
|
||||
|
|
|
|||
|
|
@ -843,8 +843,8 @@ clicon_xml2file(FILE *f,
|
|||
int level,
|
||||
int prettyprint)
|
||||
{
|
||||
cbuf *cb = NULL;
|
||||
int retval = -1;
|
||||
cbuf *cb = NULL;
|
||||
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
|
|
@ -1192,7 +1192,7 @@ copy_one(cxobj *xn0,
|
|||
* x1 should be a created placeholder. If x1 is non-empty,
|
||||
* the copied tree is appended to the existing tree.
|
||||
* @code
|
||||
* x1 = xml_new("new", xc);
|
||||
* x1 = xml_new("new", xparent);
|
||||
* xml_copy(x0, x1);
|
||||
* @endcode
|
||||
*/
|
||||
|
|
@ -1200,7 +1200,7 @@ int
|
|||
xml_copy(cxobj *x0,
|
||||
cxobj *x1)
|
||||
{
|
||||
int retval = -1;
|
||||
int retval = -1;
|
||||
cxobj *x;
|
||||
cxobj *xcopy;
|
||||
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ xmldb_plugin_load(clicon_handle h,
|
|||
/* Add API */
|
||||
if (clicon_xmldb_api_set(h, xa) < 0)
|
||||
goto done;
|
||||
clicon_log(LOG_WARNING, "xmldb plugin %s loaded", filename);
|
||||
clicon_log(LOG_DEBUG, "xmldb plugin %s loaded", filename);
|
||||
retval = 0;
|
||||
done:
|
||||
if (retval < 0 && handle)
|
||||
|
|
|
|||
|
|
@ -1125,7 +1125,7 @@ xml_tree_prune_unmarked(cxobj *xt,
|
|||
*/
|
||||
int
|
||||
xml_default(cxobj *xt,
|
||||
void *arg)
|
||||
void *arg)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *ys;
|
||||
|
|
@ -1135,7 +1135,11 @@ xml_default(cxobj *xt,
|
|||
cxobj *xb;
|
||||
char *str;
|
||||
|
||||
ys = (yang_stmt*)xml_spec(xt);
|
||||
if ((ys = (yang_stmt*)xml_spec(xt)) == NULL){
|
||||
clicon_log(LOG_WARNING, "%s: no xml_spec(%s)", __FUNCTION__, xml_name(xt));
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
/* Check leaf defaults */
|
||||
if (ys->ys_keyword == Y_CONTAINER || ys->ys_keyword == Y_LIST){
|
||||
for (i=0; i<ys->ys_len; i++){
|
||||
|
|
@ -1184,7 +1188,11 @@ xml_order(cxobj *xt,
|
|||
char *yname; /* yang child name */
|
||||
char *xname; /* xml child name */
|
||||
|
||||
y = (yang_stmt*)xml_spec(xt);
|
||||
if ((y = (yang_stmt*)xml_spec(xt)) == NULL){
|
||||
clicon_log(LOG_WARNING, "%s: no xml_spec(%s)", __FUNCTION__, xml_name(xt));
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
j0 = 0;
|
||||
/* Go through xml children and ensure they are same order as yspec children */
|
||||
for (i=0; i<y->ys_len; i++){
|
||||
|
|
@ -1217,7 +1225,7 @@ xml_order(cxobj *xt,
|
|||
}
|
||||
}
|
||||
retval = 0;
|
||||
// done:
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -1232,7 +1240,11 @@ xml_sanity(cxobj *xt,
|
|||
yang_stmt *ys;
|
||||
char *name;
|
||||
|
||||
ys = (yang_stmt*)xml_spec(xt);
|
||||
if ((ys = (yang_stmt*)xml_spec(xt)) == NULL){
|
||||
clicon_log(LOG_WARNING, "%s: no xml_spec(%s)", __FUNCTION__, xml_name(xt));
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
name = xml_name(xt);
|
||||
if (ys==NULL){
|
||||
clicon_err(OE_XML, 0, "No spec for xml node %s", name);
|
||||
|
|
@ -1248,18 +1260,33 @@ xml_sanity(cxobj *xt,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Translate from restconf api-path to xml xpath
|
||||
/*! Translate from restconf api-path in cvv form to xml xpath
|
||||
* eg a/b=c -> a/[b=c]
|
||||
* @param[in] yspec Yang spec
|
||||
* @param[in] pcvec api-path as cvec
|
||||
* @param[in] pi Length of cvec
|
||||
* @param[out] path The xpath as cligen bif variable string
|
||||
* @param[in] pi Offset of cvec, where api-path starts
|
||||
* @param[out] path The xpath as cbuf variable string, must be initializeed
|
||||
* The api-path has some wierd encoding, use api_path2xpath() if you are
|
||||
* confused.
|
||||
* It works like this:
|
||||
* Assume origin incoming path is
|
||||
* "www.foo.com/restconf/a/b=c", pi is 2 and pcvec is:
|
||||
* ["www.foo.com" "restconf" "a" "b=c"]
|
||||
* which means the api-path is ["a" "b=c"] corresponding to "a/b=c"
|
||||
* @code
|
||||
* cbuf *xpath = cbuf_new();
|
||||
* if (api_path2xpath_cvv(yspec, cvv, i, xpath)
|
||||
* err;
|
||||
* ... access xpath as cbuf_get(xpath)
|
||||
* cbuf_free(xpath)
|
||||
* @endcode
|
||||
* @see api_path2xpath for string api-path argument
|
||||
*/
|
||||
int
|
||||
xml_apipath2xpath(yang_spec *yspec,
|
||||
cvec *pcvec,
|
||||
int pi,
|
||||
cbuf *path)
|
||||
api_path2xpath_cvv(yang_spec *yspec,
|
||||
cvec *cvv,
|
||||
int offset,
|
||||
cbuf *xpath)
|
||||
{
|
||||
int retval = -1;
|
||||
int i;
|
||||
|
|
@ -1272,12 +1299,12 @@ xml_apipath2xpath(yang_spec *yspec,
|
|||
yang_stmt *ykey;
|
||||
cg_var *cvi;
|
||||
|
||||
for (i=pi; i<cvec_len(pcvec); i++){
|
||||
cv = cvec_i(pcvec, i);
|
||||
for (i=offset; i<cvec_len(cvv); i++){
|
||||
cv = cvec_i(cvv, i);
|
||||
name = cv_name_get(cv);
|
||||
clicon_debug(1, "[%d] cvname:%s", i, name);
|
||||
clicon_debug(1, "cv2str%d", cv2str(cv, NULL, 0));
|
||||
if (i == pi){
|
||||
if (i == offset){
|
||||
if ((y = yang_find_topnode(yspec, name)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "No yang node found: %s", name);
|
||||
goto done;
|
||||
|
|
@ -1313,20 +1340,53 @@ xml_apipath2xpath(yang_spec *yspec,
|
|||
goto done;
|
||||
cvi = NULL;
|
||||
/* Iterate over individual yang keys */
|
||||
cprintf(path, "/%s", name);
|
||||
cprintf(xpath, "/%s", name);
|
||||
v = val;
|
||||
while ((cvi = cvec_each(cvk, cvi)) != NULL){
|
||||
cprintf(path, "[%s=%s]", cv_string_get(cvi), v);
|
||||
cprintf(xpath, "[%s=%s]", cv_string_get(cvi), v);
|
||||
v += strlen(v)+1;
|
||||
}
|
||||
if (val)
|
||||
free(val);
|
||||
}
|
||||
else{
|
||||
cprintf(path, "%s%s", (i==pi?"":"/"), name);
|
||||
cprintf(xpath, "%s%s", (i==offset?"":"/"), name);
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Translate from restconf api-path to xml xpath
|
||||
* eg a/b=c -> a/[b=c]
|
||||
* @param[in] yspec Yang spec
|
||||
* @param[in] str API-path as string
|
||||
* @param[out] path The xpath as cbuf variable string, must be initializeed
|
||||
* @code
|
||||
* cbuf *xpath = cbuf_new();
|
||||
* if (api_path2xpath(yspec, "a/b=c", xpath)
|
||||
* err;
|
||||
* ... access xpath as cbuf_get(xpath)
|
||||
* cbuf_free(xpath)
|
||||
* @endcode
|
||||
*/
|
||||
int
|
||||
api_path2xpath(yang_spec *yspec,
|
||||
char *api_path,
|
||||
cbuf *xpath)
|
||||
{
|
||||
int retval = -1;
|
||||
cvec *api_path_cvv = NULL;
|
||||
|
||||
/* rest url eg /album=ricky/foo */
|
||||
if (str2cvec(api_path, '/', '=', &api_path_cvv) < 0)
|
||||
goto done;
|
||||
if (api_path2xpath_cvv(yspec, api_path_cvv, 0, xpath) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
if (api_path_cvv)
|
||||
cvec_free(api_path_cvv);
|
||||
return retval;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue