- removed api_path extension from internal netconf
- Strings in xmldb_put not properly encoded, eg eth/0 became eth.00000
This commit is contained in:
parent
683376610c
commit
3453dae0db
36 changed files with 1048 additions and 1307 deletions
|
|
@ -224,7 +224,7 @@ json_current_body(struct clicon_json_yacc_arg *jy,
|
|||
*/
|
||||
|
||||
/* top: json -> value is also possible */
|
||||
json : value J_EOF { clicon_debug(1,"json->object"); YYACCEPT; }
|
||||
json : value J_EOF { clicon_debug(2,"json->object"); YYACCEPT; }
|
||||
;
|
||||
|
||||
value : J_TRUE { json_current_body(_JY, "true");}
|
||||
|
|
|
|||
|
|
@ -119,9 +119,12 @@ format_str2int(char *str)
|
|||
return fv?fv->fv_int:-1;
|
||||
}
|
||||
|
||||
/*! Encode a clicon netconf message
|
||||
/*! Encode a clicon netconf message using variable argument lists
|
||||
* @param[in] format Variable agrument list format an XML netconf string
|
||||
* @retval msg Clicon message to send to eg clicon_msg_send()
|
||||
* @note if format includes %, they will be expanded according to printf rules.
|
||||
* if this is a problem, use ("%s", xml) instaead of (xml)
|
||||
* Notaly this may an issue of RFC 3896 encoded strings
|
||||
*/
|
||||
struct clicon_msg *
|
||||
clicon_msg_encode(char *format, ...)
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ clicon_rpc_get_config(clicon_handle h,
|
|||
if (xpath && strlen(xpath))
|
||||
cprintf(cb, "<filter type=\"xpath\" select=\"%s\"/>", xpath);
|
||||
cprintf(cb, "</get-config></rpc>");
|
||||
if ((msg = clicon_msg_encode(cbuf_get(cb))) == NULL)
|
||||
if ((msg = clicon_msg_encode("%s", cbuf_get(cb))) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
|
|
@ -291,13 +291,12 @@ clicon_rpc_get_config(clicon_handle h,
|
|||
* @param[in] h CLICON handle
|
||||
* @param[in] db Name of database
|
||||
* @param[in] op Operation on database item: OP_MERGE, OP_REPLACE
|
||||
* @param[in] api_path restconf API Path (or "")
|
||||
* @param[in] xml XML string. Ex: <config><a>..</a><b>...</b></config>
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @note xml arg need to have <config> as top element
|
||||
* @code
|
||||
* if (clicon_rpc_edit_config(h, "running", OP_MERGE, "/",
|
||||
* if (clicon_rpc_edit_config(h, "running", OP_MERGE,
|
||||
* "<config><a>4</a></config>") < 0)
|
||||
* err;
|
||||
* @endcode
|
||||
|
|
@ -306,7 +305,6 @@ int
|
|||
clicon_rpc_edit_config(clicon_handle h,
|
||||
char *db,
|
||||
enum operation_type op,
|
||||
char *api_path,
|
||||
char *xmlstr)
|
||||
{
|
||||
int retval = -1;
|
||||
|
|
@ -320,12 +318,10 @@ clicon_rpc_edit_config(clicon_handle h,
|
|||
cprintf(cb, "<rpc><edit-config><target><%s/></target>", db);
|
||||
cprintf(cb, "<default-operation>%s</default-operation>",
|
||||
xml_operation2str(op));
|
||||
if (api_path && strlen(api_path))
|
||||
cprintf(cb, "<filter type=\"restconf\" select=\"%s\"/>", api_path);
|
||||
if (xmlstr)
|
||||
cprintf(cb, "%s", xmlstr);
|
||||
cprintf(cb, "</edit-config></rpc>");
|
||||
if ((msg = clicon_msg_encode(cbuf_get(cb))) == NULL)
|
||||
if ((msg = clicon_msg_encode("%s", cbuf_get(cb))) == NULL)
|
||||
goto done;
|
||||
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -374,7 +374,6 @@ xmldb_get(clicon_handle h,
|
|||
* @param[in] op OP_MERGE: just add it.
|
||||
* OP_REPLACE: first delete whole database
|
||||
* OP_NONE: operation attribute in xml determines operation
|
||||
* @param[in] api_path According to restconf (Sec 3.5.1.1 in [restconf-draft 13])
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* The xml may contain the "operation" attribute which defines the operation.
|
||||
|
|
@ -382,16 +381,14 @@ xmldb_get(clicon_handle h,
|
|||
* cxobj *xt;
|
||||
* if (clicon_xml_parse_str("<a>17</a>", &xt) < 0)
|
||||
* err;
|
||||
* if (xmldb_put(xh, "running", OP_MERGE, NULL, xt) < 0)
|
||||
* if (xmldb_put(xh, "running", OP_MERGE, xt) < 0)
|
||||
* err;
|
||||
* @endcode
|
||||
* @see xmldb_put_xkey for single key
|
||||
*/
|
||||
int
|
||||
xmldb_put(clicon_handle h,
|
||||
char *db,
|
||||
enum operation_type op,
|
||||
char *api_path,
|
||||
cxobj *xt)
|
||||
{
|
||||
int retval = -1;
|
||||
|
|
@ -417,12 +414,12 @@ xmldb_put(clicon_handle h,
|
|||
if (clicon_xml2cbuf(cb, xt, 0, 0) < 0)
|
||||
goto done;
|
||||
|
||||
clicon_log(LOG_WARNING, "%s: db:%s op:%d api_path:%s xml:%s", __FUNCTION__,
|
||||
db, op, api_path, cbuf_get(cb));
|
||||
clicon_log(LOG_WARNING, "%s: db:%s op:%d xml:%s", __FUNCTION__,
|
||||
db, op, cbuf_get(cb));
|
||||
cbuf_free(cb);
|
||||
}
|
||||
#endif
|
||||
retval = xa->xa_put_fn(xh, db, op, api_path, xt);
|
||||
retval = xa->xa_put_fn(xh, db, op, xt);
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,7 +121,9 @@ tleaf(cxobj *x)
|
|||
* @param[in] level print 4 spaces per level in front of each line
|
||||
*/
|
||||
int
|
||||
xml2txt(FILE *f, cxobj *x, int level)
|
||||
xml2txt(FILE *f,
|
||||
cxobj *x,
|
||||
int level)
|
||||
{
|
||||
cxobj *xe = NULL;
|
||||
int children=0;
|
||||
|
|
@ -799,13 +801,13 @@ xml_diff(yang_spec *yspec,
|
|||
* yang: container a -> list b -> key c -> leaf d
|
||||
* xpath: /a/b/%s/d
|
||||
* @param[in] ys Yang statement
|
||||
* @param[in] inclkey If inclkey then include key leaf (eg last leaf d in ex)
|
||||
* @param[out] cbuf keyfmt
|
||||
* @param[in] inclkey If set include key leaf (eg last leaf d in ex)
|
||||
* @param[out] cb api_path_fmt,
|
||||
*/
|
||||
static int
|
||||
yang2xmlkeyfmt_1(yang_stmt *ys,
|
||||
int inclkey,
|
||||
cbuf *cb)
|
||||
yang2api_path_fmt_1(yang_stmt *ys,
|
||||
int inclkey,
|
||||
cbuf *cb)
|
||||
{
|
||||
yang_node *yp; /* parent */
|
||||
yang_stmt *ykey;
|
||||
|
|
@ -817,7 +819,7 @@ yang2xmlkeyfmt_1(yang_stmt *ys,
|
|||
if (yp != NULL &&
|
||||
yp->yn_keyword != Y_MODULE &&
|
||||
yp->yn_keyword != Y_SUBMODULE){
|
||||
if (yang2xmlkeyfmt_1((yang_stmt *)yp, 1, cb) < 0)
|
||||
if (yang2api_path_fmt_1((yang_stmt *)yp, 1, cb) < 0)
|
||||
goto done;
|
||||
}
|
||||
if (inclkey){
|
||||
|
|
@ -825,11 +827,14 @@ yang2xmlkeyfmt_1(yang_stmt *ys,
|
|||
cprintf(cb, "/%s", ys->ys_argument);
|
||||
}
|
||||
else{
|
||||
if (ys->ys_keyword == Y_LEAF && yp && yp->yn_keyword == Y_LIST){
|
||||
#if 1
|
||||
if (ys->ys_keyword == Y_LEAF && yp &&
|
||||
yp->yn_keyword == Y_LIST){
|
||||
if (yang_key_match(yp, ys->ys_argument) == 0)
|
||||
cprintf(cb, "/%s", ys->ys_argument); /* Not if leaf and key */
|
||||
}
|
||||
else
|
||||
else
|
||||
#endif
|
||||
if (ys->ys_keyword != Y_CHOICE && ys->ys_keyword != Y_CASE)
|
||||
cprintf(cb, "/%s", ys->ys_argument);
|
||||
}
|
||||
|
|
@ -866,19 +871,19 @@ yang2xmlkeyfmt_1(yang_stmt *ys,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Construct an xml key format from yang statement using wildcards for keys
|
||||
/*! Construct an api_path_format from yang statement using wildcards for keys
|
||||
* Recursively construct it to the top.
|
||||
* Example:
|
||||
* yang: container a -> list b -> key c -> leaf d
|
||||
* xpath: /a/b=%s/d
|
||||
* @param[in] ys Yang statement
|
||||
* @param[in] inclkey If !inclkey then dont include key leaf
|
||||
* @param[out] xkfmt XML key format. Needs to be freed after use.
|
||||
* api_path: /a/b=%s/d
|
||||
* @param[in] ys Yang statement
|
||||
* @param[in] inclkey If set include key leaf (eg last leaf d in ex)
|
||||
* @param[out] api_path_fmt XML api path. Needs to be freed after use.
|
||||
*/
|
||||
int
|
||||
yang2xmlkeyfmt(yang_stmt *ys,
|
||||
int inclkey,
|
||||
char **xkfmt)
|
||||
yang2api_path_fmt(yang_stmt *ys,
|
||||
int inclkey,
|
||||
char **api_path_fmt)
|
||||
{
|
||||
int retval = -1;
|
||||
cbuf *cb = NULL;
|
||||
|
|
@ -887,9 +892,9 @@ yang2xmlkeyfmt(yang_stmt *ys,
|
|||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if (yang2xmlkeyfmt_1(ys, inclkey, cb) < 0)
|
||||
if (yang2api_path_fmt_1(ys, inclkey, cb) < 0)
|
||||
goto done;
|
||||
if ((*xkfmt = strdup(cbuf_get(cb))) == NULL){
|
||||
if ((*api_path_fmt = strdup(cbuf_get(cb))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -904,19 +909,20 @@ yang2xmlkeyfmt(yang_stmt *ys,
|
|||
/*! Transform an xml key format and a vector of values to an XML key
|
||||
* Used for actual key, eg in clicon_rpc_change(), xmldb_put_xkey()
|
||||
* Example:
|
||||
* xmlkeyfmt: /aaa/%s
|
||||
* xmlkeyfmt: /aaa/%s/name
|
||||
* cvv: key=17
|
||||
* xmlkey: /aaa/17
|
||||
* @param[in] xkfmt XML key format, eg /aaa/%s
|
||||
* @param[in] cvv cligen variable vector, one for every wildchar in xkfmt
|
||||
* @param[out] xk XML key, eg /aaa/17. Free after use
|
||||
* xmlkey: /aaa/17/name
|
||||
* @param[in] api_path_fmt XML key format, eg /aaa/%s/name
|
||||
* @param[in] cvv cligen variable vector, one for every wildchar in api_path_fmt
|
||||
* @param[out] api_path api_path, eg /aaa/17. Free after use
|
||||
* @param[out] yang_arg yang-stmt argument name. Free after use
|
||||
* @note first and last elements of cvv are not used,..
|
||||
* @see cli_dbxml where this function is called
|
||||
*/
|
||||
int
|
||||
xmlkeyfmt2key(char *xkfmt,
|
||||
cvec *cvv,
|
||||
char **xk)
|
||||
api_path_fmt2api_path(char *api_path_fmt,
|
||||
cvec *cvv,
|
||||
char **api_path)
|
||||
{
|
||||
int retval = -1;
|
||||
char c;
|
||||
|
|
@ -927,16 +933,15 @@ xmlkeyfmt2key(char *xkfmt,
|
|||
char *str;
|
||||
char *strenc=NULL;
|
||||
|
||||
|
||||
/* Sanity check */
|
||||
#if 1
|
||||
j = 0; /* Count % */
|
||||
for (i=0; i<strlen(xkfmt); i++)
|
||||
if (xkfmt[i] == '%')
|
||||
for (i=0; i<strlen(api_path_fmt); i++)
|
||||
if (api_path_fmt[i] == '%')
|
||||
j++;
|
||||
if (j+2 < cvec_len(cvv)) {
|
||||
clicon_log(LOG_WARNING, "%s xmlkey format string mismatch(j=%d, cvec_len=%d): %s",
|
||||
xkfmt,
|
||||
api_path_fmt,
|
||||
j,
|
||||
cvec_len(cvv),
|
||||
cv_string_get(cvec_i(cvv, 0)));
|
||||
|
|
@ -948,8 +953,8 @@ xmlkeyfmt2key(char *xkfmt,
|
|||
goto done;
|
||||
}
|
||||
j = 1; /* j==0 is cli string */
|
||||
for (i=0; i<strlen(xkfmt); i++){
|
||||
c = xkfmt[i];
|
||||
for (i=0; i<strlen(api_path_fmt); i++){
|
||||
c = api_path_fmt[i];
|
||||
if (esc){
|
||||
esc = 0;
|
||||
if (c!='s')
|
||||
|
|
@ -967,10 +972,13 @@ xmlkeyfmt2key(char *xkfmt,
|
|||
else
|
||||
if (c == '%')
|
||||
esc++;
|
||||
else if (c == '/'){
|
||||
cprintf(cb, "%c", c);
|
||||
}
|
||||
else
|
||||
cprintf(cb, "%c", c);
|
||||
}
|
||||
if ((*xk = strdup(cbuf_get(cb))) == NULL){
|
||||
if ((*api_path = strdup(cbuf_get(cb))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -993,14 +1001,14 @@ xmlkeyfmt2key(char *xkfmt,
|
|||
* xmlkeyfmt: /ip/me/%s (if key)
|
||||
* cvv: -
|
||||
* xmlkey: /ipv4/me/a
|
||||
* @param[in] xkfmt XML key format
|
||||
* @param[in] cvv cligen variable vector, one for every wildchar in xkfmt
|
||||
* @param[out] xk XPATH
|
||||
* @param[in] api_path_fmt XML key format
|
||||
* @param[in] cvv cligen variable vector, one for every wildchar in api_path_fmt
|
||||
* @param[out] xpath XPATH
|
||||
*/
|
||||
int
|
||||
xmlkeyfmt2xpath(char *xkfmt,
|
||||
cvec *cvv,
|
||||
char **xk)
|
||||
api_path_fmt2xpath(char *api_path_fmt,
|
||||
cvec *cvv,
|
||||
char **xpath)
|
||||
{
|
||||
int retval = -1;
|
||||
char c;
|
||||
|
|
@ -1015,12 +1023,12 @@ xmlkeyfmt2xpath(char *xkfmt,
|
|||
/* Sanity check: count '%' */
|
||||
#if 1
|
||||
j = 0; /* Count % */
|
||||
for (i=0; i<strlen(xkfmt); i++)
|
||||
if (xkfmt[i] == '%')
|
||||
for (i=0; i<strlen(api_path_fmt); i++)
|
||||
if (api_path_fmt[i] == '%')
|
||||
j++;
|
||||
if (j < cvec_len(cvv)-1) {
|
||||
clicon_log(LOG_WARNING, "%s xmlkey format string mismatch(j=%d, cvec_len=%d): %s",
|
||||
xkfmt,
|
||||
api_path_fmt,
|
||||
j,
|
||||
cvec_len(cvv),
|
||||
cv_string_get(cvec_i(cvv, 0)));
|
||||
|
|
@ -1032,8 +1040,8 @@ xmlkeyfmt2xpath(char *xkfmt,
|
|||
goto done;
|
||||
}
|
||||
j = 1; /* j==0 is cli string */
|
||||
for (i=0; i<strlen(xkfmt); i++){
|
||||
c = xkfmt[i];
|
||||
for (i=0; i<strlen(api_path_fmt); i++){
|
||||
c = api_path_fmt[i];
|
||||
if (esc){
|
||||
esc = 0;
|
||||
if (c!='s')
|
||||
|
|
@ -1059,13 +1067,13 @@ xmlkeyfmt2xpath(char *xkfmt,
|
|||
if (skip)
|
||||
skip=0;
|
||||
else
|
||||
if ((c == '=' || c == ',') && xkfmt[i+1]=='%')
|
||||
if ((c == '=' || c == ',') && api_path_fmt[i+1]=='%')
|
||||
; /* skip */
|
||||
else
|
||||
cprintf(cb, "%c", c);
|
||||
}
|
||||
}
|
||||
if ((*xk = strdup4(cbuf_get(cb))) == NULL){
|
||||
if ((*xpath = strdup4(cbuf_get(cb))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -1094,13 +1102,17 @@ xml_tree_prune_flagged(cxobj *xt,
|
|||
int test,
|
||||
int *upmark)
|
||||
{
|
||||
int retval = -1;
|
||||
int submark;
|
||||
int mark;
|
||||
cxobj *x;
|
||||
cxobj *xprev;
|
||||
int retval = -1;
|
||||
int submark;
|
||||
int mark;
|
||||
cxobj *x;
|
||||
cxobj *xprev;
|
||||
int iskey;
|
||||
int anykey=0;
|
||||
yang_node *yt;
|
||||
|
||||
mark = 0;
|
||||
yt = xml_spec(xt);
|
||||
x = NULL;
|
||||
xprev = x = NULL;
|
||||
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
|
||||
|
|
@ -1109,8 +1121,20 @@ xml_tree_prune_flagged(cxobj *xt,
|
|||
xprev = x;
|
||||
continue; /* mark and stop here */
|
||||
}
|
||||
/* If it is key dont remove it yet (see second round) */
|
||||
if (yt){
|
||||
if ((iskey = yang_key_match(yt, xml_name(x))) < 0)
|
||||
goto done;
|
||||
if (iskey){
|
||||
anykey++;
|
||||
xprev = x; /* skip if this is key */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (xml_tree_prune_flagged(x, flag, test, &submark) < 0)
|
||||
goto done;
|
||||
/* if xt is list and submark anywhere, then key subs are also marked
|
||||
*/
|
||||
if (submark)
|
||||
mark++;
|
||||
else{ /* Safe with xml_child_each if last */
|
||||
|
|
@ -1120,6 +1144,22 @@ xml_tree_prune_flagged(cxobj *xt,
|
|||
}
|
||||
xprev = x;
|
||||
}
|
||||
/* Second round: if any keys were found, and no marks detected, purge now */
|
||||
if (anykey && !mark){
|
||||
x = NULL;
|
||||
xprev = x = NULL;
|
||||
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
|
||||
/* If it is key remove it here */
|
||||
if (yt){
|
||||
if ((iskey = yang_key_match(yt, xml_name(x))) < 0)
|
||||
goto done;
|
||||
if (iskey && xml_purge(x) < 0)
|
||||
goto done;
|
||||
x = xprev;
|
||||
}
|
||||
xprev = x;
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (upmark)
|
||||
|
|
@ -1397,3 +1437,181 @@ api_path2xpath(yang_spec *yspec,
|
|||
cvec_free(api_path_cvv);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Create xml tree from api-path as vector
|
||||
* @param[in] vec APIpath as char* vector
|
||||
* @param[in] nvec Length of vec
|
||||
* @param[in] x0 Xpath tree so far
|
||||
* @param[in] y0 Yang spec for x0
|
||||
* @param[out] xpathp Resulting xml tree
|
||||
* @param[out] ypathp Yang spec matching xpathp
|
||||
* @see api_path2xml
|
||||
*/
|
||||
static int
|
||||
api_path2xml_vec(char **vec,
|
||||
int nvec,
|
||||
cxobj *x0,
|
||||
yang_node *y0,
|
||||
cxobj **xpathp,
|
||||
yang_node **ypathp)
|
||||
{
|
||||
int retval = -1;
|
||||
int j;
|
||||
char *name;
|
||||
char *restval = NULL;
|
||||
char *restval_enc;
|
||||
yang_stmt *ykey;
|
||||
cxobj *xn = NULL; /* new */
|
||||
cxobj *xb; /* body */
|
||||
cvec *cvk = NULL; /* vector of index keys */
|
||||
cg_var *cvi;
|
||||
char *keyname;
|
||||
char *val2;
|
||||
char **valvec = NULL;
|
||||
int nvalvec;
|
||||
cxobj *x = NULL;
|
||||
yang_stmt *y = NULL;
|
||||
|
||||
if ((name = vec[0]) == NULL){
|
||||
*xpathp = x0;
|
||||
*ypathp = y0;
|
||||
return 0;
|
||||
} /* E.g "x=1,2" -> name:x restval=1,2 */
|
||||
/* restval is RFC 3896 encoded */
|
||||
if ((restval_enc = index(name, '=')) != NULL){
|
||||
*restval_enc = '\0';
|
||||
restval_enc++;
|
||||
if (percent_decode(restval_enc, &restval) < 0)
|
||||
goto done;
|
||||
}
|
||||
if (y0->yn_keyword == Y_SPEC) /* top-node */
|
||||
y = yang_find_topnode((yang_spec*)y0, name);
|
||||
else
|
||||
y = yang_find_syntax((yang_node*)y0, name);
|
||||
if (y == NULL){
|
||||
clicon_err(OE_YANG, errno, "No yang node found: %s", name);
|
||||
goto done;
|
||||
}
|
||||
switch (y->ys_keyword){
|
||||
case Y_LEAF_LIST:
|
||||
if (restval==NULL){
|
||||
clicon_err(OE_XML, 0, "malformed key, expected '=<restval>'");
|
||||
goto done;
|
||||
}
|
||||
if ((x = xml_new_spec(y->ys_argument, x0, y)) == NULL)
|
||||
goto done;
|
||||
xml_type_set(x, CX_ELMNT);
|
||||
if ((xb = xml_new("body", x)) == NULL)
|
||||
goto done;
|
||||
xml_type_set(xb, CX_BODY);
|
||||
if (xml_value_set(xb, restval) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case Y_LIST:
|
||||
/* Get the yang list key */
|
||||
if ((ykey = yang_find((yang_node*)y, Y_KEY, NULL)) == NULL){
|
||||
clicon_err(OE_XML, errno, "%s: List statement \"%s\" has no key",
|
||||
__FUNCTION__, y->ys_argument);
|
||||
goto done;
|
||||
}
|
||||
/* The value is a list of keys: <key>[ <key>]* */
|
||||
if ((cvk = yang_arg2cvec(ykey, " ")) == NULL)
|
||||
goto done;
|
||||
if (restval==NULL){
|
||||
clicon_err(OE_XML, 0, "malformed key, expected '=<restval>'");
|
||||
goto done;
|
||||
}
|
||||
if (valvec)
|
||||
free(valvec);
|
||||
if ((valvec = clicon_strsep(restval, ",", &nvalvec)) == NULL)
|
||||
goto done;
|
||||
|
||||
if (cvec_len(cvk) != nvalvec){
|
||||
clicon_err(OE_XML, errno, "List %s key length mismatch", name);
|
||||
goto done;
|
||||
}
|
||||
cvi = NULL;
|
||||
/* create list object */
|
||||
if ((x = xml_new_spec(name, x0, y)) == NULL)
|
||||
goto done;
|
||||
xml_type_set(x, CX_ELMNT);
|
||||
j = 0;
|
||||
/* Create keys */
|
||||
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
|
||||
keyname = cv_string_get(cvi);
|
||||
val2 = valvec[j++];
|
||||
if ((xn = xml_new(keyname, x)) == NULL)
|
||||
goto done;
|
||||
xml_type_set(xn, CX_ELMNT);
|
||||
if ((xb = xml_new("body", xn)) == NULL)
|
||||
goto done;
|
||||
xml_type_set(xb, CX_BODY);
|
||||
if (xml_value_set(xb, val2) <0)
|
||||
goto done;
|
||||
}
|
||||
if (cvk){
|
||||
cvec_free(cvk);
|
||||
cvk = NULL;
|
||||
}
|
||||
break;
|
||||
default: /* eg Y_CONTAINER, Y_LEAF */
|
||||
if ((x = xml_new_spec(name, x0, y)) == NULL)
|
||||
goto done;
|
||||
xml_type_set(x, CX_ELMNT);
|
||||
break;
|
||||
}
|
||||
if (api_path2xml_vec(vec+1, nvec-1,
|
||||
x, (yang_node*)y,
|
||||
xpathp, ypathp) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
if (restval)
|
||||
free(restval);
|
||||
if (valvec)
|
||||
free(valvec);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Create xml tree from api-path
|
||||
* @param[in] api_path API-path as defined in RFC 8040
|
||||
* @param[out] xpathp Resulting xml tree
|
||||
* @param[out] ypathp Yang spec matching xpathp
|
||||
* @see api_path2xml_vec
|
||||
*/
|
||||
int
|
||||
api_path2xml(char *api_path,
|
||||
yang_spec *yspec,
|
||||
cxobj *xpath,
|
||||
cxobj **xpathp,
|
||||
yang_node **ypathp)
|
||||
{
|
||||
int retval = -1;
|
||||
char **vec = NULL;
|
||||
int nvec;
|
||||
|
||||
clicon_debug(1, "%s 0", __FUNCTION__);
|
||||
if (*api_path!='/'){
|
||||
clicon_err(OE_DB, 0, "Invalid key: %s", api_path);
|
||||
goto done;
|
||||
}
|
||||
if ((vec = clicon_strsep(api_path, "/", &nvec)) == NULL)
|
||||
goto done;
|
||||
/* Remove trailing '/'. Like in /a/ -> /a */
|
||||
if (nvec > 1 && !strlen(vec[nvec-1]))
|
||||
nvec--;
|
||||
if (nvec < 1){
|
||||
clicon_err(OE_XML, 0, "Malformed key: %s", api_path);
|
||||
goto done;
|
||||
}
|
||||
nvec--; /* NULL-terminated */
|
||||
if (api_path2xml_vec(vec+1, nvec,
|
||||
xpath, (yang_node*)yspec,
|
||||
xpathp, ypathp) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
if (vec)
|
||||
free(vec);
|
||||
return retval;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,23 +79,6 @@ clixon_xml_parseerror(void *_ya, char *s)
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
xml_attr_new(struct xml_parse_yacc_arg *ya,
|
||||
cxobj *xn,
|
||||
char *name,
|
||||
char *val)
|
||||
{
|
||||
cxobj *xa;
|
||||
|
||||
if ((xa = xml_new(name, xn)) == NULL)
|
||||
return -1;
|
||||
xml_type_set(xa, CX_ATTR);
|
||||
if (xml_value_set(xa, val) < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* note that we dont handle escaped characters correctly
|
||||
there may also be some leakage here on NULL return
|
||||
*/
|
||||
|
|
@ -194,17 +177,21 @@ xml_parse_bslash1(struct xml_parse_yacc_arg *ya,
|
|||
xml_namespace(x), xml_name(x), name);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* remove all non-terminal bodies (strip pretty-print) */
|
||||
/* Strip pretty-print. Ad-hoc algorithm
|
||||
* It ok with x:[body], but not with x:[ex,body]
|
||||
* It is also ok with x:[attr,body]
|
||||
* So the rule is: if there is at least on element, then remove all bodies?
|
||||
*/
|
||||
if (ya->ya_skipspace){
|
||||
if (xml_child_nr(x) == 1 && (xml_type(xml_child_i(x, 0))==CX_BODY))
|
||||
;
|
||||
else{
|
||||
xc = NULL;
|
||||
while ((xc = xml_child_each(x, xc, CX_ELMNT)) != NULL)
|
||||
break;
|
||||
if (xc != NULL){ /* at least one element */
|
||||
xc = NULL;
|
||||
while ((xc = xml_child_each(x, xc, CX_BODY)) != NULL) {
|
||||
xml_purge(xc);
|
||||
xc = NULL; /* reset iterator */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
|
|
@ -240,14 +227,20 @@ xml_parse_bslash2(struct xml_parse_yacc_arg *ya,
|
|||
name);
|
||||
goto done;
|
||||
}
|
||||
/* remove all non-terminal bodies (strip pretty-print) */
|
||||
/* Strip pretty-print. Ad-hoc algorithm
|
||||
* It ok with x:[body], but not with x:[ex,body]
|
||||
* It is also ok with x:[attr,body]
|
||||
* So the rule is: if there is at least on element, then remove all bodies?
|
||||
*/
|
||||
if (ya->ya_skipspace){
|
||||
if (xml_child_nr(x) == 1 && (xml_type(xml_child_i(x, 0))==CX_BODY))
|
||||
;
|
||||
else{
|
||||
xc = NULL;
|
||||
while ((xc = xml_child_each(x, xc, CX_ELMNT)) != NULL)
|
||||
break;
|
||||
if (xc != NULL){ /* at least one element */
|
||||
xc = NULL;
|
||||
while ((xc = xml_child_each(x, xc, CX_BODY)) != NULL)
|
||||
while ((xc = xml_child_each(x, xc, CX_BODY)) != NULL) {
|
||||
xml_value_set(xc, ""); /* XXX remove */
|
||||
}
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
|
|
@ -276,8 +269,12 @@ static int
|
|||
xml_parse_attr(struct xml_parse_yacc_arg *ya, char *id, char *val)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xa;
|
||||
|
||||
if (xml_attr_new(ya, ya->ya_xelement, id, val) < 0)
|
||||
if ((xa = xml_new(id, ya->ya_xelement)) == NULL)
|
||||
goto done;
|
||||
xml_type_set(xa, CX_ATTR);
|
||||
if (xml_value_set(xa, val) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue