* Added new cli show functions to work with cligen_output for cligen pageing to work. To acheive this, add a callback function as follows:
* xml2txt(...) --> xml2txt_cb(..., cligen_output) * xml2cli(...) --> xml2cli_cb(..., cligen_output) * clicon_xml2file(...) --> clicon_xml2file_cb(..., cligen_output) * xml2json(...) --> xml2json_cb(..., cligen_output) * yang_print(...) --> yang_print_cb(..., cligen_output)
This commit is contained in:
parent
6e714beea5
commit
0adcd94f3f
13 changed files with 291 additions and 114 deletions
|
|
@ -42,12 +42,19 @@ Expected: July 2020
|
||||||
|
|
||||||
### API changes on existing protocol/config features (For users)
|
### API changes on existing protocol/config features (For users)
|
||||||
|
|
||||||
* Restconf FCGI (eg via nginx) have changed reply message syntax as follows (due to refactoring and common code with evhtp):
|
* Restconf FCGI (eg via nginx) have changed reply message syntax slightly as follows (due to refactoring and common code with evhtp):
|
||||||
* Bodies in error reyruns including html code have been removed
|
* Bodies in error reyruns including html code have been removed
|
||||||
* Some (extra) CRLF:s have been removed
|
* Some (extra) CRLF:s have been removed
|
||||||
|
|
||||||
### C/CLI-API changes on existing features (For developers)
|
### C/CLI-API changes on existing features (For developers)
|
||||||
|
|
||||||
|
* Added new cli show functions to work with cligen_output for cligen pageing to work. To acheive this, add a callback function as follows:
|
||||||
|
* xml2txt(...) --> xml2txt_cb(..., cligen_output)
|
||||||
|
* xml2cli(...) --> xml2cli_cb(..., cligen_output)
|
||||||
|
* clicon_xml2file(...) --> clicon_xml2file_cb(..., cligen_output)
|
||||||
|
* xml2json(...) --> xml2json_cb(..., cligen_output)
|
||||||
|
* yang_print(...) --> yang_print_cb(..., cligen_output)
|
||||||
|
|
||||||
* Added prefix for cli_show_config/cli_show_auto so that it can produce parseable output
|
* Added prefix for cli_show_config/cli_show_auto so that it can produce parseable output
|
||||||
* Replaced the global variable `debug` with access function: `clicon_debug_get()`.
|
* Replaced the global variable `debug` with access function: `clicon_debug_get()`.
|
||||||
* Due to name collision with libevent, all clixon event functions prepended with `clixon_`. You need to rename your event functions as follows:
|
* Due to name collision with libevent, all clixon event functions prepended with `clixon_`. You need to rename your event functions as follows:
|
||||||
|
|
|
||||||
|
|
@ -652,10 +652,10 @@ compare_xmls(cxobj *xc1,
|
||||||
xc = NULL;
|
xc = NULL;
|
||||||
if (astext)
|
if (astext)
|
||||||
while ((xc = xml_child_each(xc1, xc, -1)) != NULL)
|
while ((xc = xml_child_each(xc1, xc, -1)) != NULL)
|
||||||
xml2txt(f, xc, 0);
|
xml2txt_cb(f, xc, cligen_output);
|
||||||
else
|
else
|
||||||
while ((xc = xml_child_each(xc1, xc, -1)) != NULL)
|
while ((xc = xml_child_each(xc1, xc, -1)) != NULL)
|
||||||
xml_print(f, xc);
|
clicon_xml2file_cb(f, xc, 0, 1, cligen_output);
|
||||||
|
|
||||||
fclose(f);
|
fclose(f);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
@ -669,10 +669,10 @@ compare_xmls(cxobj *xc1,
|
||||||
xc = NULL;
|
xc = NULL;
|
||||||
if (astext)
|
if (astext)
|
||||||
while ((xc = xml_child_each(xc2, xc, -1)) != NULL)
|
while ((xc = xml_child_each(xc2, xc, -1)) != NULL)
|
||||||
xml2txt(f, xc, 0);
|
xml2txt_cb(f, xc, cligen_output);
|
||||||
else
|
else
|
||||||
while ((xc = xml_child_each(xc2, xc, -1)) != NULL)
|
while ((xc = xml_child_each(xc2, xc, -1)) != NULL)
|
||||||
xml_print(f, xc);
|
clicon_xml2file_cb(f, xc, 0, 1, cligen_output);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
|
|
@ -1002,15 +1002,15 @@ cli_notification_cb(int s,
|
||||||
while ((x = xml_child_each(xe, x, -1)) != NULL) {
|
while ((x = xml_child_each(xe, x, -1)) != NULL) {
|
||||||
switch (format){
|
switch (format){
|
||||||
case FORMAT_XML:
|
case FORMAT_XML:
|
||||||
if (clicon_xml2file(stdout, x, 0, 1) < 0)
|
if (clicon_xml2file_cb(stdout, x, 0, 1, cligen_output) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
case FORMAT_TEXT:
|
case FORMAT_TEXT:
|
||||||
if (xml2txt(stdout, x, 0) < 0)
|
if (xml2txt_cb(stdout, x, cligen_output) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
case FORMAT_JSON:
|
case FORMAT_JSON:
|
||||||
if (xml2json(stdout, x, 1) < 0)
|
if (xml2json_cb(stdout, x, 1, cligen_output) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -406,7 +406,7 @@ show_yang(clicon_handle h,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
yn = yspec;
|
yn = yspec;
|
||||||
yang_print(stdout, yn);
|
yang_print_cb(stdout, yn, cligen_output); /* Doesnt use cligen_output */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -506,15 +506,15 @@ cli_show_config1(clicon_handle h,
|
||||||
case FORMAT_XML:
|
case FORMAT_XML:
|
||||||
xc = NULL; /* Dont print xt itself */
|
xc = NULL; /* Dont print xt itself */
|
||||||
while ((xc = xml_child_each(xt, xc, -1)) != NULL)
|
while ((xc = xml_child_each(xt, xc, -1)) != NULL)
|
||||||
clicon_xml2file(stdout, xc, 0, 1);
|
clicon_xml2file_cb(stdout, xc, 0, 1, cligen_output);
|
||||||
break;
|
break;
|
||||||
case FORMAT_JSON:
|
case FORMAT_JSON:
|
||||||
xml2json(stdout, xt, 1);
|
xml2json_cb(stdout, xt, 1, cligen_output);
|
||||||
break;
|
break;
|
||||||
case FORMAT_TEXT:
|
case FORMAT_TEXT:
|
||||||
xc = NULL; /* Dont print xt itself */
|
xc = NULL; /* Dont print xt itself */
|
||||||
while ((xc = xml_child_each(xt, xc, -1)) != NULL)
|
while ((xc = xml_child_each(xt, xc, -1)) != NULL)
|
||||||
xml2txt(stdout, xc, 0); /* tree-formed text */
|
xml2txt_cb(stdout, xc, cligen_output); /* tree-formed text */
|
||||||
break;
|
break;
|
||||||
case FORMAT_CLI:
|
case FORMAT_CLI:
|
||||||
/* get CLI generatade mode: VARS|ALL */
|
/* get CLI generatade mode: VARS|ALL */
|
||||||
|
|
@ -522,14 +522,14 @@ cli_show_config1(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
xc = NULL; /* Dont print xt itself */
|
xc = NULL; /* Dont print xt itself */
|
||||||
while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL)
|
while ((xc = xml_child_each(xt, xc, CX_ELMNT)) != NULL)
|
||||||
xml2cli(stdout, xc, prefix, gt); /* cli syntax */
|
xml2cli_cb(stdout, xc, prefix, gt, cligen_output); /* cli syntax */
|
||||||
break;
|
break;
|
||||||
case FORMAT_NETCONF:
|
case FORMAT_NETCONF:
|
||||||
fprintf(stdout, "<rpc><edit-config><target><candidate/></target><config>\n");
|
cligen_output(stdout, "<rpc><edit-config><target><candidate/></target><config>\n");
|
||||||
xc = NULL; /* Dont print xt itself */
|
xc = NULL; /* Dont print xt itself */
|
||||||
while ((xc = xml_child_each(xt, xc, -1)) != NULL)
|
while ((xc = xml_child_each(xt, xc, -1)) != NULL)
|
||||||
clicon_xml2file(stdout, xc, 2, 1);
|
clicon_xml2file_cb(stdout, xc, 2, 1, cligen_output);
|
||||||
fprintf(stdout, "</config></edit-config></rpc>]]>]]>\n");
|
cligen_output(stdout, "</config></edit-config></rpc>]]>]]>\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -763,15 +763,15 @@ cli_show_auto1(clicon_handle h,
|
||||||
clicon_xml2file(stdout, xp, 0, 1);
|
clicon_xml2file(stdout, xp, 0, 1);
|
||||||
break;
|
break;
|
||||||
case FORMAT_JSON:
|
case FORMAT_JSON:
|
||||||
xml2json(stdout, xp, 1);
|
xml2json_cb(stdout, xp, 1, cligen_output);
|
||||||
break;
|
break;
|
||||||
case FORMAT_TEXT:
|
case FORMAT_TEXT:
|
||||||
xml2txt(stdout, xp, 0); /* tree-formed text */
|
xml2txt_cb(stdout, xp, cligen_output); /* tree-formed text */
|
||||||
break;
|
break;
|
||||||
case FORMAT_CLI:
|
case FORMAT_CLI:
|
||||||
if ((gt = clicon_cli_genmodel_type(h)) == GT_ERR)
|
if ((gt = clicon_cli_genmodel_type(h)) == GT_ERR)
|
||||||
goto done;
|
goto done;
|
||||||
xml2cli(stdout, xp, prefix, gt); /* cli syntax */
|
xml2cli_cb(stdout, xp, prefix, gt, cligen_output); /* cli syntax */
|
||||||
break;
|
break;
|
||||||
case FORMAT_NETCONF:
|
case FORMAT_NETCONF:
|
||||||
fprintf(stdout, "<rpc><edit-config><target><candidate/></target><config>\n");
|
fprintf(stdout, "<rpc><edit-config><target><candidate/></target><config>\n");
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ mycallback(clicon_handle h, cvec *cvv, cvec *argv)
|
||||||
nsc,
|
nsc,
|
||||||
&xret) < 0)
|
&xret) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
xml_print(stdout, xret);
|
clicon_xml2file_cb(stdout, xret, 0, 1, cligen_output);
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
if (nsc)
|
if (nsc)
|
||||||
|
|
@ -117,11 +117,11 @@ example_client_rpc(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
/* Print result */
|
/* Print result */
|
||||||
clicon_xml2file(stdout, xml_child_i(xret, 0), 0, 0);
|
clicon_xml2file_cb(stdout, xml_child_i(xret, 0), 0, 0, cligen_output);
|
||||||
fprintf(stdout,"\n");
|
fprintf(stdout,"\n");
|
||||||
|
|
||||||
/* pretty-print:
|
/* pretty-print:
|
||||||
xml2txt(stdout, xml_child_i(xret, 0), 0);
|
xml2txt_cb(stdout, xml_child_i(xret, 0), cligen_output);
|
||||||
*/
|
*/
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,20 @@ typedef void *clicon_handle;
|
||||||
/* The dynamicically loadable plugin object handle (should be in clixon_plugin.h) */
|
/* The dynamicically loadable plugin object handle (should be in clixon_plugin.h) */
|
||||||
typedef void *plghndl_t;
|
typedef void *plghndl_t;
|
||||||
|
|
||||||
|
/*! Indirect output functions to print with something else than fprintf
|
||||||
|
* @param[in] h Clicon handle
|
||||||
|
* @param[in] xn Request: <rpc><xn></rpc>
|
||||||
|
* @param[out] cbret Return xml tree, eg <rpc-reply>..., <rpc-error..
|
||||||
|
* @param[in] arg Domain specific arg, ec client-entry or FCGX_Request
|
||||||
|
* @param[in] regarg User argument given at rpc_callback_register()
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
*/
|
||||||
|
typedef int (clicon_output_cb)(
|
||||||
|
FILE *f,
|
||||||
|
const char *templ, ...
|
||||||
|
) __attribute__ ((format (printf, 2, 3)));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ int json2xml_decode(cxobj *x, cxobj **xerr);
|
||||||
int xml2json_cbuf(cbuf *cb, cxobj *x, int pretty);
|
int xml2json_cbuf(cbuf *cb, cxobj *x, int pretty);
|
||||||
int xml2json_cbuf_vec(cbuf *cb, cxobj **vec, size_t veclen, int pretty);
|
int xml2json_cbuf_vec(cbuf *cb, cxobj **vec, size_t veclen, int pretty);
|
||||||
int xml2json(FILE *f, cxobj *x, int pretty);
|
int xml2json(FILE *f, cxobj *x, int pretty);
|
||||||
|
int xml2json_cb(FILE *f, cxobj *x, int pretty, clicon_output_cb *fn);
|
||||||
int json_print(FILE *f, cxobj *x);
|
int json_print(FILE *f, cxobj *x);
|
||||||
int xml2json_vec(FILE *f, cxobj **vec, size_t veclen, int pretty);
|
int xml2json_vec(FILE *f, cxobj **vec, size_t veclen, int pretty);
|
||||||
int clixon_json_parse_string(char *str, yang_bind yb, yang_stmt *yspec, cxobj **xt, cxobj **xret);
|
int clixon_json_parse_string(char *str, yang_bind yb, yang_stmt *yspec, cxobj **xt, cxobj **xret);
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@
|
||||||
/*
|
/*
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
|
int clicon_xml2file_cb(FILE *f, cxobj *x, int level, int prettyprint, clicon_output_cb *fn);
|
||||||
int clicon_xml2file(FILE *f, cxobj *x, int level, int prettyprint);
|
int clicon_xml2file(FILE *f, cxobj *x, int level, int prettyprint);
|
||||||
int xml_print(FILE *f, cxobj *xn);
|
int xml_print(FILE *f, cxobj *xn);
|
||||||
int clicon_xml2cbuf(cbuf *cb, cxobj *x, int level, int prettyprint, int32_t depth);
|
int clicon_xml2cbuf(cbuf *cb, cxobj *x, int level, int prettyprint, int32_t depth);
|
||||||
|
|
|
||||||
|
|
@ -40,14 +40,19 @@
|
||||||
#ifndef _CLIXON_XML_MAP_H_
|
#ifndef _CLIXON_XML_MAP_H_
|
||||||
#define _CLIXON_XML_MAP_H_
|
#define _CLIXON_XML_MAP_H_
|
||||||
|
|
||||||
/* declared in clixon_yang_internal */
|
/*
|
||||||
|
* Types
|
||||||
|
*/
|
||||||
|
/* Declared in clixon_yang_internal */
|
||||||
typedef enum yang_class yang_class;
|
typedef enum yang_class yang_class;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prototypes
|
* Prototypes
|
||||||
*/
|
*/
|
||||||
int isxmlns(cxobj *x);
|
int isxmlns(cxobj *x);
|
||||||
|
int xml2txt_cb(FILE *f, cxobj *x, clicon_output_cb *fn);
|
||||||
int xml2txt(FILE *f, cxobj *x, int level);
|
int xml2txt(FILE *f, cxobj *x, int level);
|
||||||
|
int xml2cli_cb(FILE *f, cxobj *x, char *prepend, enum genmodel_type gt, clicon_output_cb *fn);
|
||||||
int xml2cli(FILE *f, cxobj *x, char *prepend, enum genmodel_type gt);
|
int xml2cli(FILE *f, cxobj *x, char *prepend, enum genmodel_type gt);
|
||||||
int xmlns_assign(cxobj *x);
|
int xmlns_assign(cxobj *x);
|
||||||
int xml2cvec(cxobj *xt, yang_stmt *ys, cvec **cvv0);
|
int xml2cvec(cxobj *xt, yang_stmt *ys, cvec **cvv0);
|
||||||
|
|
|
||||||
|
|
@ -227,6 +227,7 @@ int yang_find_prefix_by_namespace(yang_stmt *ys, char *namespace, char **
|
||||||
yang_stmt *yang_myroot(yang_stmt *ys);
|
yang_stmt *yang_myroot(yang_stmt *ys);
|
||||||
yang_stmt *yang_choice(yang_stmt *y);
|
yang_stmt *yang_choice(yang_stmt *y);
|
||||||
int yang_order(yang_stmt *y);
|
int yang_order(yang_stmt *y);
|
||||||
|
int yang_print_cb(FILE *f, yang_stmt *yn, clicon_output_cb *fn);
|
||||||
int yang_print(FILE *f, yang_stmt *yn);
|
int yang_print(FILE *f, yang_stmt *yn);
|
||||||
int yang_print_cbuf(cbuf *cb, yang_stmt *yn, int marginal);
|
int yang_print_cbuf(cbuf *cb, yang_stmt *yn, int marginal);
|
||||||
int if_feature(yang_stmt *yspec, char *module, char *feature);
|
int if_feature(yang_stmt *yspec, char *module, char *feature);
|
||||||
|
|
|
||||||
|
|
@ -1007,6 +1007,43 @@ xml2json_cbuf_vec(cbuf *cb,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Translate from xml tree to JSON and print to file using a callback
|
||||||
|
* @param[in] f File to print to
|
||||||
|
* @param[in] x XML tree to translate from
|
||||||
|
* @param[in] pretty Set if output is pretty-printed
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
*
|
||||||
|
* @note yang is necessary to translate to one-member lists,
|
||||||
|
* eg if a is a yang LIST <a>0</a> -> {"a":["0"]} and not {"a":"0"}
|
||||||
|
* @code
|
||||||
|
* if (xml2json(stderr, xn, 0) < 0)
|
||||||
|
* goto err;
|
||||||
|
* @endcode
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml2json_cb(FILE *f,
|
||||||
|
cxobj *x,
|
||||||
|
int pretty,
|
||||||
|
clicon_output_cb *fn)
|
||||||
|
{
|
||||||
|
int retval = 1;
|
||||||
|
cbuf *cb = NULL;
|
||||||
|
|
||||||
|
if ((cb = cbuf_new()) ==NULL){
|
||||||
|
clicon_err(OE_XML, errno, "cbuf_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (xml2json_cbuf(cb, x, pretty) < 0)
|
||||||
|
goto done;
|
||||||
|
(*fn)(f, "%s", cbuf_get(cb));
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (cb)
|
||||||
|
cbuf_free(cb);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Translate from xml tree to JSON and print to file
|
/*! Translate from xml tree to JSON and print to file
|
||||||
* @param[in] f File to print to
|
* @param[in] f File to print to
|
||||||
* @param[in] x XML tree to translate from
|
* @param[in] x XML tree to translate from
|
||||||
|
|
@ -1026,22 +1063,9 @@ xml2json(FILE *f,
|
||||||
cxobj *x,
|
cxobj *x,
|
||||||
int pretty)
|
int pretty)
|
||||||
{
|
{
|
||||||
int retval = 1;
|
return xml2json_cb(f, x, pretty, fprintf);
|
||||||
cbuf *cb = NULL;
|
}
|
||||||
|
|
||||||
if ((cb = cbuf_new()) ==NULL){
|
|
||||||
clicon_err(OE_XML, errno, "cbuf_new");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (xml2json_cbuf(cb, x, pretty) < 0)
|
|
||||||
goto done;
|
|
||||||
fprintf(f, "%s", cbuf_get(cb));
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
if (cb)
|
|
||||||
cbuf_free(cb);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*! Print an XML tree structure to an output stream as JSON
|
/*! Print an XML tree structure to an output stream as JSON
|
||||||
*
|
*
|
||||||
|
|
@ -1050,9 +1074,9 @@ xml2json(FILE *f,
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
json_print(FILE *f,
|
json_print(FILE *f,
|
||||||
cxobj *xn)
|
cxobj *x)
|
||||||
{
|
{
|
||||||
return xml2json(f, xn, 1);
|
return xml2json_cb(f, x, 1, fprintf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Translate a vector of xml objects to JSON File.
|
/*! Translate a vector of xml objects to JSON File.
|
||||||
|
|
|
||||||
|
|
@ -96,15 +96,17 @@
|
||||||
* @param[in] xn clicon xml tree
|
* @param[in] xn clicon xml tree
|
||||||
* @param[in] level how many spaces to insert before each line
|
* @param[in] level how many spaces to insert before each line
|
||||||
* @param[in] prettyprint insert \n and spaces tomake the xml more readable.
|
* @param[in] prettyprint insert \n and spaces tomake the xml more readable.
|
||||||
|
* @param[in] fn Callback to make print function
|
||||||
* @see clicon_xml2cbuf
|
* @see clicon_xml2cbuf
|
||||||
* One can use clicon_xml2cbuf to get common code, but using fprintf is
|
* One can use clicon_xml2cbuf to get common code, but using fprintf is
|
||||||
* much faster than using cbuf and then printing that,...
|
* much faster than using cbuf and then printing that,...
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
clicon_xml2file(FILE *f,
|
xml2file_recurse(FILE *f,
|
||||||
cxobj *x,
|
cxobj *x,
|
||||||
int level,
|
int level,
|
||||||
int prettyprint)
|
int prettyprint,
|
||||||
|
clicon_output_cb *fn)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *name;
|
char *name;
|
||||||
|
|
@ -125,19 +127,19 @@ clicon_xml2file(FILE *f,
|
||||||
break;
|
break;
|
||||||
if (xml_chardata_encode(&encstr, "%s", val) < 0)
|
if (xml_chardata_encode(&encstr, "%s", val) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
fprintf(f, "%s", encstr);
|
(*fn)(f, "%s", encstr);
|
||||||
break;
|
break;
|
||||||
case CX_ATTR:
|
case CX_ATTR:
|
||||||
fprintf(f, " ");
|
(*fn)(f, " ");
|
||||||
if (namespace)
|
if (namespace)
|
||||||
fprintf(f, "%s:", namespace);
|
(*fn)(f, "%s:", namespace);
|
||||||
fprintf(f, "%s=\"%s\"", name, xml_value(x));
|
(*fn)(f, "%s=\"%s\"", name, xml_value(x));
|
||||||
break;
|
break;
|
||||||
case CX_ELMNT:
|
case CX_ELMNT:
|
||||||
fprintf(f, "%*s<", prettyprint?(level*XML_INDENT):0, "");
|
(*fn)(f, "%*s<", prettyprint?(level*XML_INDENT):0, "");
|
||||||
if (namespace)
|
if (namespace)
|
||||||
fprintf(f, "%s:", namespace);
|
(*fn)(f, "%s:", namespace);
|
||||||
fprintf(f, "%s", name);
|
(*fn)(f, "%s", name);
|
||||||
hasbody = 0;
|
hasbody = 0;
|
||||||
haselement = 0;
|
haselement = 0;
|
||||||
xc = NULL;
|
xc = NULL;
|
||||||
|
|
@ -145,7 +147,7 @@ clicon_xml2file(FILE *f,
|
||||||
while ((xc = xml_child_each(x, xc, -1)) != NULL) {
|
while ((xc = xml_child_each(x, xc, -1)) != NULL) {
|
||||||
switch (xml_type(xc)){
|
switch (xml_type(xc)){
|
||||||
case CX_ATTR:
|
case CX_ATTR:
|
||||||
if (clicon_xml2file(f, xc, level+1, prettyprint) <0)
|
if (xml2file_recurse(f, xc, level+1, prettyprint, fn) <0)
|
||||||
goto done;
|
goto done;
|
||||||
break;
|
break;
|
||||||
case CX_BODY:
|
case CX_BODY:
|
||||||
|
|
@ -162,26 +164,26 @@ clicon_xml2file(FILE *f,
|
||||||
* Ie, no CX_BODY or CX_ELMNT child.
|
* Ie, no CX_BODY or CX_ELMNT child.
|
||||||
*/
|
*/
|
||||||
if (hasbody==0 && haselement==0)
|
if (hasbody==0 && haselement==0)
|
||||||
fprintf(f, "/>");
|
(*fn)(f, "/>");
|
||||||
else{
|
else{
|
||||||
fprintf(f, ">");
|
(*fn)(f, ">");
|
||||||
if (prettyprint && hasbody == 0)
|
if (prettyprint && hasbody == 0)
|
||||||
fprintf(f, "\n");
|
(*fn)(f, "\n");
|
||||||
xc = NULL;
|
xc = NULL;
|
||||||
while ((xc = xml_child_each(x, xc, -1)) != NULL) {
|
while ((xc = xml_child_each(x, xc, -1)) != NULL) {
|
||||||
if (xml_type(xc) != CX_ATTR)
|
if (xml_type(xc) != CX_ATTR)
|
||||||
if (clicon_xml2file(f, xc, level+1, prettyprint) <0)
|
if (xml2file_recurse(f, xc, level+1, prettyprint, fn) <0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (prettyprint && hasbody==0)
|
if (prettyprint && hasbody==0)
|
||||||
fprintf(f, "%*s", level*XML_INDENT, "");
|
(*fn)(f, "%*s", level*XML_INDENT, "");
|
||||||
fprintf(f, "</");
|
(*fn)(f, "</");
|
||||||
if (namespace)
|
if (namespace)
|
||||||
fprintf(f, "%s:", namespace);
|
(*fn)(f, "%s:", namespace);
|
||||||
fprintf(f, "%s>", name);
|
(*fn)(f, "%s>", name);
|
||||||
}
|
}
|
||||||
if (prettyprint)
|
if (prettyprint)
|
||||||
fprintf(f, "\n");
|
(*fn)(f, "\n");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
@ -194,6 +196,42 @@ clicon_xml2file(FILE *f,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Print an XML tree structure to an output stream and encode chars "<>&"
|
||||||
|
*
|
||||||
|
* @param[in] f UNIX output stream
|
||||||
|
* @param[in] xn clicon xml tree
|
||||||
|
* @param[in] level how many spaces to insert before each line
|
||||||
|
* @param[in] prettyprint insert \n and spaces tomake the xml more readable.
|
||||||
|
* @see clicon_xml2cbuf print to a cbuf string
|
||||||
|
* @see clicon_xml2cbuf_cb print using a callback
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
clicon_xml2file(FILE *f,
|
||||||
|
cxobj *x,
|
||||||
|
int level,
|
||||||
|
int prettyprint)
|
||||||
|
{
|
||||||
|
return xml2file_recurse(f, x, level, prettyprint, fprintf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Print an XML tree structure to an output stream and encode chars "<>&"
|
||||||
|
*
|
||||||
|
* @param[in] f UNIX output stream
|
||||||
|
* @param[in] xn clicon xml tree
|
||||||
|
* @param[in] level how many spaces to insert before each line
|
||||||
|
* @param[in] prettyprint insert \n and spaces tomake the xml more readable.
|
||||||
|
* @see clicon_xml2cbuf
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
clicon_xml2file_cb(FILE *f,
|
||||||
|
cxobj *x,
|
||||||
|
int level,
|
||||||
|
int prettyprint,
|
||||||
|
clicon_output_cb *fn)
|
||||||
|
{
|
||||||
|
return xml2file_recurse(f, x, level, prettyprint, fn);
|
||||||
|
}
|
||||||
|
|
||||||
/*! Print an XML tree structure to an output stream
|
/*! Print an XML tree structure to an output stream
|
||||||
*
|
*
|
||||||
* Uses clicon_xml2file internally
|
* Uses clicon_xml2file internally
|
||||||
|
|
@ -201,13 +239,13 @@ clicon_xml2file(FILE *f,
|
||||||
* @param[in] f UNIX output stream
|
* @param[in] f UNIX output stream
|
||||||
* @param[in] xn clicon xml tree
|
* @param[in] xn clicon xml tree
|
||||||
* @see clicon_xml2cbuf
|
* @see clicon_xml2cbuf
|
||||||
* @see clicon_xml2file
|
* @see clicon_xml2cbuf_cb print using a callback
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xml_print(FILE *f,
|
xml_print(FILE *f,
|
||||||
cxobj *xn)
|
cxobj *x)
|
||||||
{
|
{
|
||||||
return clicon_xml2file(f, xn, 0, 1);
|
return xml2file_recurse(f, x, 0, 1, fprintf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Print an XML tree structure to a cligen buffer and encode chars "<>&"
|
/*! Print an XML tree structure to a cligen buffer and encode chars "<>&"
|
||||||
|
|
|
||||||
|
|
@ -129,19 +129,26 @@ tleaf(cxobj *x)
|
||||||
return (xml_child_nr_notype(xc, CX_ATTR) == 0);
|
return (xml_child_nr_notype(xc, CX_ATTR) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Translate XML -> TEXT
|
/*! Translate XML to a "pseudo-code" textual format using a callback - internal function
|
||||||
|
* @param[in] f File to print to
|
||||||
|
* @param[in] x XML object to print
|
||||||
|
* @param[in] fn Callback to make print function
|
||||||
* @param[in] level print 4 spaces per level in front of each line
|
* @param[in] level print 4 spaces per level in front of each line
|
||||||
* XXX rewrite using YANG and remove encrypted password KLUDGE
|
|
||||||
*/
|
*/
|
||||||
int
|
static int
|
||||||
xml2txt(FILE *f,
|
xml2txt_recurse(FILE *f,
|
||||||
cxobj *x,
|
cxobj *x,
|
||||||
|
clicon_output_cb *fn,
|
||||||
int level)
|
int level)
|
||||||
{
|
{
|
||||||
cxobj *xc = NULL;
|
cxobj *xc = NULL;
|
||||||
int children=0;
|
int children=0;
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
|
|
||||||
|
if (f == NULL || x == NULL || fn == NULL){
|
||||||
|
clicon_err(OE_XML, EINVAL, "f, x or fn is NULL");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
xc = NULL; /* count children (elements and bodies, not attributes) */
|
xc = NULL; /* count children (elements and bodies, not attributes) */
|
||||||
while ((xc = xml_child_each(x, xc, -1)) != NULL)
|
while ((xc = xml_child_each(x, xc, -1)) != NULL)
|
||||||
if (xml_type(xc) == CX_ELMNT || xml_type(xc) == CX_BODY)
|
if (xml_type(xc) == CX_ELMNT || xml_type(xc) == CX_BODY)
|
||||||
|
|
@ -149,48 +156,76 @@ xml2txt(FILE *f,
|
||||||
if (!children){ /* If no children print line */
|
if (!children){ /* If no children print line */
|
||||||
switch (xml_type(x)){
|
switch (xml_type(x)){
|
||||||
case CX_BODY:
|
case CX_BODY:
|
||||||
fprintf(f, "%s;\n", xml_value(x));
|
(*fn)(f, "%s;\n", xml_value(x));
|
||||||
break;
|
break;
|
||||||
case CX_ELMNT:
|
case CX_ELMNT:
|
||||||
fprintf(f, "%*s;\n", 4*level, xml_name(x));
|
(*fn)(f, "%*s;\n", 4*level, xml_name(x));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
fprintf(f, "%*s", 4*level, "");
|
(*fn)(f, "%*s", 4*level, "");
|
||||||
fprintf(f, "%s ", xml_name(x));
|
(*fn)(f, "%s ", xml_name(x));
|
||||||
if (!tleaf(x))
|
if (!tleaf(x))
|
||||||
fprintf(f, "{\n");
|
(*fn)(f, "{\n");
|
||||||
xc = NULL;
|
xc = NULL;
|
||||||
while ((xc = xml_child_each(x, xc, -1)) != NULL){
|
while ((xc = xml_child_each(x, xc, -1)) != NULL){
|
||||||
if (xml_type(xc) == CX_ELMNT || xml_type(xc) == CX_BODY)
|
if (xml_type(xc) == CX_ELMNT || xml_type(xc) == CX_BODY)
|
||||||
if (xml2txt(f, xc, level+1) < 0)
|
if (xml2txt_recurse(f, xc, fn, level+1) < 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!tleaf(x))
|
if (!tleaf(x))
|
||||||
fprintf(f, "%*s}\n", 4*level, "");
|
(*fn)(f, "%*s}\n", 4*level, "");
|
||||||
ok:
|
ok:
|
||||||
retval = 0;
|
retval = 0;
|
||||||
// done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Translate XML to a "pseudo-code" textual format using a callback
|
||||||
|
* @param[in] f File to print to
|
||||||
|
* @param[in] x XML object to print
|
||||||
|
* @param[in] fn Callback to make print function
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml2txt_cb(FILE *f,
|
||||||
|
cxobj *x,
|
||||||
|
clicon_output_cb *fn)
|
||||||
|
{
|
||||||
|
return xml2txt_recurse(f, x, fn, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Translate XML to a "pseudo-code" textual format using stdio file
|
||||||
|
* @param[in] f File to print to
|
||||||
|
* @param[in] x XML object to print
|
||||||
|
* @param[in] level print 4 spaces per level in front of each line
|
||||||
|
* @see xml2txt_cb
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml2txt(FILE *f,
|
||||||
|
cxobj *x,
|
||||||
|
int level)
|
||||||
|
{
|
||||||
|
return xml2txt_recurse(f, x, fprintf, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/*! Translate from XML to CLI commands
|
/*! Translate from XML to CLI commands
|
||||||
* Howto: join strings and pass them down.
|
* Howto: join strings and pass them down.
|
||||||
* Identify unique/index keywords for correct set syntax.
|
* Identify unique/index keywords for correct set syntax.
|
||||||
* Args:
|
|
||||||
* @param[in] f Where to print cli commands
|
* @param[in] f Where to print cli commands
|
||||||
* @param[in] x XML Parse-tree (to translate)
|
* @param[in] x XML Parse-tree (to translate)
|
||||||
* @param[in] prepend0 Print this text in front of all commands.
|
* @param[in] prepend Print this text in front of all commands.
|
||||||
* @param[in] gt option to steer cli syntax
|
* @param[in] gt option to steer cli syntax
|
||||||
|
* @param[in] fn Callback to make print function
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xml2cli(FILE *f,
|
xml2cli_recurse(FILE *f,
|
||||||
cxobj *x,
|
cxobj *x,
|
||||||
char *prepend0,
|
char *prepend,
|
||||||
enum genmodel_type gt)
|
enum genmodel_type gt,
|
||||||
|
clicon_output_cb *fn)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cxobj *xe = NULL;
|
cxobj *xe = NULL;
|
||||||
|
|
@ -204,17 +239,17 @@ xml2cli(FILE *f,
|
||||||
if ((ys = xml_spec(x)) == NULL)
|
if ((ys = xml_spec(x)) == NULL)
|
||||||
goto ok;
|
goto ok;
|
||||||
if (yang_keyword_get(ys) == Y_LEAF || yang_keyword_get(ys) == Y_LEAF_LIST){
|
if (yang_keyword_get(ys) == Y_LEAF || yang_keyword_get(ys) == Y_LEAF_LIST){
|
||||||
if (prepend0)
|
if (prepend)
|
||||||
fprintf(f, "%s", prepend0);
|
(*fn)(f, "%s", prepend);
|
||||||
if (gt == GT_ALL || gt == GT_VARS || gt == GT_HIDE)
|
if (gt == GT_ALL || gt == GT_VARS || gt == GT_HIDE)
|
||||||
fprintf(f, "%s ", xml_name(x));
|
(*fn)(f, "%s ", xml_name(x));
|
||||||
if ((body = xml_body(x)) != NULL){
|
if ((body = xml_body(x)) != NULL){
|
||||||
if (index(body, ' '))
|
if (index(body, ' '))
|
||||||
fprintf(f, "\"%s\"", body);
|
(*fn)(f, "\"%s\"", body);
|
||||||
else
|
else
|
||||||
fprintf(f, "%s", body);
|
(*fn)(f, "%s", body);
|
||||||
}
|
}
|
||||||
fprintf(f, "\n");
|
(*fn)(f, "\n");
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
/* Create prepend variable string */
|
/* Create prepend variable string */
|
||||||
|
|
@ -222,8 +257,8 @@ xml2cli(FILE *f,
|
||||||
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
clicon_err(OE_PLUGIN, errno, "cbuf_new");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (prepend0)
|
if (prepend)
|
||||||
cprintf(cbpre, "%s", prepend0);
|
cprintf(cbpre, "%s", prepend);
|
||||||
|
|
||||||
/* If non-presence container && HIDE mode && only child is
|
/* If non-presence container && HIDE mode && only child is
|
||||||
* a list, then skip container keyword
|
* a list, then skip container keyword
|
||||||
|
|
@ -251,11 +286,11 @@ xml2cli(FILE *f,
|
||||||
if ((match = yang_key_match(ys, xml_name(xe))) < 0)
|
if ((match = yang_key_match(ys, xml_name(xe))) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (match){
|
if (match){
|
||||||
fprintf(f, "%s\n", cbuf_get(cbpre));
|
(*fn)(f, "%s\n", cbuf_get(cbpre));
|
||||||
continue; /* Not key itself */
|
continue; /* Not key itself */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (xml2cli(f, xe, cbuf_get(cbpre), gt) < 0)
|
if (xml2cli_recurse(f, xe, cbuf_get(cbpre), gt, fn) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
ok:
|
ok:
|
||||||
|
|
@ -266,6 +301,43 @@ xml2cli(FILE *f,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Translate from XML to CLI commands
|
||||||
|
* Howto: join strings and pass them down.
|
||||||
|
* Identify unique/index keywords for correct set syntax.
|
||||||
|
* @param[in] f Where to print cli commands
|
||||||
|
* @param[in] x XML Parse-tree (to translate)
|
||||||
|
* @param[in] prepend Print this text in front of all commands.
|
||||||
|
* @param[in] gt option to steer cli syntax
|
||||||
|
* @param[in] fn Callback to make print function
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml2cli_cb(FILE *f,
|
||||||
|
cxobj *x,
|
||||||
|
char *prepend,
|
||||||
|
enum genmodel_type gt,
|
||||||
|
clicon_output_cb *fn)
|
||||||
|
{
|
||||||
|
return xml2cli_recurse(f, x, prepend, gt, fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Translate from XML to CLI commands
|
||||||
|
* Howto: join strings and pass them down.
|
||||||
|
* Identify unique/index keywords for correct set syntax.
|
||||||
|
* Args:
|
||||||
|
* @param[in] f Where to print cli commands
|
||||||
|
* @param[in] x XML Parse-tree (to translate)
|
||||||
|
* @param[in] prepend Print this text in front of all commands.
|
||||||
|
* @param[in] gt option to steer cli syntax
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml2cli(FILE *f,
|
||||||
|
cxobj *x,
|
||||||
|
char *prepend,
|
||||||
|
enum genmodel_type gt)
|
||||||
|
{
|
||||||
|
return xml2cli_recurse(f, x, prepend, gt, fprintf);
|
||||||
|
}
|
||||||
|
|
||||||
/*! Translate a single xml node to a cligen variable vector. Note not recursive
|
/*! Translate a single xml node to a cligen variable vector. Note not recursive
|
||||||
* @param[in] xt XML tree containing one top node
|
* @param[in] xt XML tree containing one top node
|
||||||
* @param[in] ys Yang spec containing type specification of top-node of xt
|
* @param[in] ys Yang spec containing type specification of top-node of xt
|
||||||
|
|
|
||||||
|
|
@ -1247,11 +1247,13 @@ quotedstring(char *s)
|
||||||
/*! Print yang specification to file
|
/*! Print yang specification to file
|
||||||
* @param[in] f File to print to.
|
* @param[in] f File to print to.
|
||||||
* @param[in] yn Yang node to print
|
* @param[in] yn Yang node to print
|
||||||
|
* @param[in] fn Callback to make print function
|
||||||
* @see yang_print_cbuf
|
* @see yang_print_cbuf
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
yang_print(FILE *f,
|
yang_print_cb(FILE *f,
|
||||||
yang_stmt *yn)
|
yang_stmt *yn,
|
||||||
|
clicon_output_cb *fn)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
cbuf *cb = NULL;
|
cbuf *cb = NULL;
|
||||||
|
|
@ -1262,7 +1264,7 @@ yang_print(FILE *f,
|
||||||
}
|
}
|
||||||
if (yang_print_cbuf(cb, yn, 0) < 0)
|
if (yang_print_cbuf(cb, yn, 0) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
fprintf(f, "%s", cbuf_get(cb));
|
(*fn)(f, "%s", cbuf_get(cb));
|
||||||
if (cb)
|
if (cb)
|
||||||
cbuf_free(cb);
|
cbuf_free(cb);
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -1270,6 +1272,18 @@ yang_print(FILE *f,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Print yang specification to file
|
||||||
|
* @param[in] f File to print to.
|
||||||
|
* @param[in] yn Yang node to print
|
||||||
|
* @see yang_print_cbuf
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
yang_print(FILE *f,
|
||||||
|
yang_stmt *yn)
|
||||||
|
{
|
||||||
|
return yang_print_cb(f, yn, fprintf);
|
||||||
|
}
|
||||||
|
|
||||||
/*! Print yang specification to cligen buf
|
/*! Print yang specification to cligen buf
|
||||||
* @param[in] cb Cligen buffer. This is where the pretty print is.
|
* @param[in] cb Cligen buffer. This is where the pretty print is.
|
||||||
* @param[in] yn Yang node to print
|
* @param[in] yn Yang node to print
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue