* 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:
Olof hagsand 2020-06-17 14:04:19 +02:00
parent 6e714beea5
commit 0adcd94f3f
13 changed files with 291 additions and 114 deletions

View file

@ -1007,6 +1007,43 @@ xml2json_cbuf_vec(cbuf *cb,
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
* @param[in] f File to print to
* @param[in] x XML tree to translate from
@ -1026,23 +1063,10 @@ xml2json(FILE *f,
cxobj *x,
int pretty)
{
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;
fprintf(f, "%s", cbuf_get(cb));
retval = 0;
done:
if (cb)
cbuf_free(cb);
return retval;
return xml2json_cb(f, x, pretty, fprintf);
}
/*! Print an XML tree structure to an output stream as JSON
*
* @param[in] f UNIX output stream
@ -1050,9 +1074,9 @@ xml2json(FILE *f,
*/
int
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.

View file

@ -96,15 +96,17 @@
* @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.
* @param[in] fn Callback to make print function
* @see clicon_xml2cbuf
* One can use clicon_xml2cbuf to get common code, but using fprintf is
* much faster than using cbuf and then printing that,...
*/
int
clicon_xml2file(FILE *f,
cxobj *x,
int level,
int prettyprint)
xml2file_recurse(FILE *f,
cxobj *x,
int level,
int prettyprint,
clicon_output_cb *fn)
{
int retval = -1;
char *name;
@ -125,19 +127,19 @@ clicon_xml2file(FILE *f,
break;
if (xml_chardata_encode(&encstr, "%s", val) < 0)
goto done;
fprintf(f, "%s", encstr);
(*fn)(f, "%s", encstr);
break;
case CX_ATTR:
fprintf(f, " ");
(*fn)(f, " ");
if (namespace)
fprintf(f, "%s:", namespace);
fprintf(f, "%s=\"%s\"", name, xml_value(x));
(*fn)(f, "%s:", namespace);
(*fn)(f, "%s=\"%s\"", name, xml_value(x));
break;
case CX_ELMNT:
fprintf(f, "%*s<", prettyprint?(level*XML_INDENT):0, "");
(*fn)(f, "%*s<", prettyprint?(level*XML_INDENT):0, "");
if (namespace)
fprintf(f, "%s:", namespace);
fprintf(f, "%s", name);
(*fn)(f, "%s:", namespace);
(*fn)(f, "%s", name);
hasbody = 0;
haselement = 0;
xc = NULL;
@ -145,7 +147,7 @@ clicon_xml2file(FILE *f,
while ((xc = xml_child_each(x, xc, -1)) != NULL) {
switch (xml_type(xc)){
case CX_ATTR:
if (clicon_xml2file(f, xc, level+1, prettyprint) <0)
if (xml2file_recurse(f, xc, level+1, prettyprint, fn) <0)
goto done;
break;
case CX_BODY:
@ -162,26 +164,26 @@ clicon_xml2file(FILE *f,
* Ie, no CX_BODY or CX_ELMNT child.
*/
if (hasbody==0 && haselement==0)
fprintf(f, "/>");
(*fn)(f, "/>");
else{
fprintf(f, ">");
(*fn)(f, ">");
if (prettyprint && hasbody == 0)
fprintf(f, "\n");
(*fn)(f, "\n");
xc = NULL;
while ((xc = xml_child_each(x, xc, -1)) != NULL) {
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;
}
if (prettyprint && hasbody==0)
fprintf(f, "%*s", level*XML_INDENT, "");
fprintf(f, "</");
(*fn)(f, "%*s", level*XML_INDENT, "");
(*fn)(f, "</");
if (namespace)
fprintf(f, "%s:", namespace);
fprintf(f, "%s>", name);
(*fn)(f, "%s:", namespace);
(*fn)(f, "%s>", name);
}
if (prettyprint)
fprintf(f, "\n");
(*fn)(f, "\n");
break;
default:
break;
@ -194,6 +196,42 @@ clicon_xml2file(FILE *f,
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
*
* Uses clicon_xml2file internally
@ -201,13 +239,13 @@ clicon_xml2file(FILE *f,
* @param[in] f UNIX output stream
* @param[in] xn clicon xml tree
* @see clicon_xml2cbuf
* @see clicon_xml2file
* @see clicon_xml2cbuf_cb print using a callback
*/
int
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 "<>&"

View file

@ -129,19 +129,26 @@ tleaf(cxobj *x)
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
* XXX rewrite using YANG and remove encrypted password KLUDGE
*/
int
xml2txt(FILE *f,
cxobj *x,
int level)
static int
xml2txt_recurse(FILE *f,
cxobj *x,
clicon_output_cb *fn,
int level)
{
cxobj *xc = NULL;
int children=0;
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) */
while ((xc = xml_child_each(x, xc, -1)) != NULL)
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 */
switch (xml_type(x)){
case CX_BODY:
fprintf(f, "%s;\n", xml_value(x));
(*fn)(f, "%s;\n", xml_value(x));
break;
case CX_ELMNT:
fprintf(f, "%*s;\n", 4*level, xml_name(x));
(*fn)(f, "%*s;\n", 4*level, xml_name(x));
break;
default:
break;
}
goto ok;
}
fprintf(f, "%*s", 4*level, "");
fprintf(f, "%s ", xml_name(x));
(*fn)(f, "%*s", 4*level, "");
(*fn)(f, "%s ", xml_name(x));
if (!tleaf(x))
fprintf(f, "{\n");
(*fn)(f, "{\n");
xc = NULL;
while ((xc = xml_child_each(x, xc, -1)) != NULL){
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;
}
if (!tleaf(x))
fprintf(f, "%*s}\n", 4*level, "");
(*fn)(f, "%*s}\n", 4*level, "");
ok:
retval = 0;
// done:
done:
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
* 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] prepend0 Print this text in front of all commands.
* @param[in] gt option to steer cli 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(FILE *f,
cxobj *x,
char *prepend0,
enum genmodel_type gt)
xml2cli_recurse(FILE *f,
cxobj *x,
char *prepend,
enum genmodel_type gt,
clicon_output_cb *fn)
{
int retval = -1;
cxobj *xe = NULL;
@ -204,17 +239,17 @@ xml2cli(FILE *f,
if ((ys = xml_spec(x)) == NULL)
goto ok;
if (yang_keyword_get(ys) == Y_LEAF || yang_keyword_get(ys) == Y_LEAF_LIST){
if (prepend0)
fprintf(f, "%s", prepend0);
if (prepend)
(*fn)(f, "%s", prepend);
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 (index(body, ' '))
fprintf(f, "\"%s\"", body);
(*fn)(f, "\"%s\"", body);
else
fprintf(f, "%s", body);
(*fn)(f, "%s", body);
}
fprintf(f, "\n");
(*fn)(f, "\n");
goto ok;
}
/* Create prepend variable string */
@ -222,8 +257,8 @@ xml2cli(FILE *f,
clicon_err(OE_PLUGIN, errno, "cbuf_new");
goto done;
}
if (prepend0)
cprintf(cbpre, "%s", prepend0);
if (prepend)
cprintf(cbpre, "%s", prepend);
/* If non-presence container && HIDE mode && only child is
* a list, then skip container keyword
@ -251,11 +286,11 @@ xml2cli(FILE *f,
if ((match = yang_key_match(ys, xml_name(xe))) < 0)
goto done;
if (match){
fprintf(f, "%s\n", cbuf_get(cbpre));
(*fn)(f, "%s\n", cbuf_get(cbpre));
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;
}
ok:
@ -266,6 +301,43 @@ xml2cli(FILE *f,
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
* @param[in] xt XML tree containing one top node
* @param[in] ys Yang spec containing type specification of top-node of xt

View file

@ -1245,13 +1245,15 @@ quotedstring(char *s)
}
/*! Print yang specification to file
* @param[in] f File to print to.
* @param[in] yn Yang node to print
* @param[in] f File to print to.
* @param[in] yn Yang node to print
* @param[in] fn Callback to make print function
* @see yang_print_cbuf
*/
int
yang_print(FILE *f,
yang_stmt *yn)
yang_print_cb(FILE *f,
yang_stmt *yn,
clicon_output_cb *fn)
{
int retval = -1;
cbuf *cb = NULL;
@ -1262,7 +1264,7 @@ yang_print(FILE *f,
}
if (yang_print_cbuf(cb, yn, 0) < 0)
goto done;
fprintf(f, "%s", cbuf_get(cb));
(*fn)(f, "%s", cbuf_get(cb));
if (cb)
cbuf_free(cb);
retval = 0;
@ -1270,6 +1272,18 @@ yang_print(FILE *f,
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
* @param[in] cb Cligen buffer. This is where the pretty print is.
* @param[in] yn Yang node to print