CLI show compare example function

Improved diff algorithm for XML and TEXT/curly, replaced UNIX diff with structural in-mem algorithm
Fixed: ["show compare" and "show compare | display cli" differs #23](https://github.com/clicon/clixon-controller/issues/23)
Changed parameters of example clispec function `compare_dbs()`
Added show2cbuf functions for TEXT/CLI
Renamed clixon_txt2file to clixon_text2file
This commit is contained in:
Olof hagsand 2023-09-22 10:26:09 +02:00
parent 45f41e3e4d
commit 2603b6f139
19 changed files with 1170 additions and 193 deletions

View file

@ -557,7 +557,7 @@ cli_show_common(clicon_handle h,
cligen_output(stdout, "\n");
break;
case FORMAT_TEXT: /* XXX does not handle multiple leaf-list */
if (clixon_txt2file(stdout, xp, 0, cligen_output, skiptop, 1) < 0)
if (clixon_text2file(stdout, xp, 0, cligen_output, skiptop, 1) < 0)
goto done;
break;
case FORMAT_CLI:
@ -1299,7 +1299,7 @@ cli_pagination(clicon_handle h,
goto done;
break;
case FORMAT_TEXT:
if (clixon_txt2file(stdout, xc, 0, cligen_output, 0, 1) < 0)
if (clixon_text2file(stdout, xc, 0, cligen_output, 0, 1) < 0)
goto done;
break;
case FORMAT_CLI:
@ -1341,6 +1341,134 @@ cli_pagination(clicon_handle h,
return retval;
}
/*! Translate to CLI commands in cbuf
*
* Howto: join strings and pass them down.
* Identify unique/index keywords for correct set syntax.
* @param[in] h Clicon handle
* @param[in,out] cb Cligen buffer to write to
* @param[in] xn XML Parse-tree (to translate)
* @param[in] prepend Print this text in front of all commands.
* @retval 0 OK
* @retval -1 Error
* @see clixon_cli2file
*/
static int
cli2cbuf(clicon_handle h,
cbuf *cb,
cxobj *xn,
char *prepend)
{
int retval = -1;
cxobj *xe = NULL;
cbuf *cbpre = NULL;
yang_stmt *ys;
int match;
char *body;
int compress = 0;
autocli_listkw_t listkw;
int exist = 0;
char *name;
if (autocli_list_keyword(h, &listkw) < 0)
goto done;
if (xml_type(xn)==CX_ATTR)
goto ok;
if ((ys = xml_spec(xn)) == NULL)
goto ok;
if (yang_extension_value(ys, "hide-show", CLIXON_AUTOCLI_NS, &exist, NULL) < 0)
goto done;
if (exist)
goto ok;
exist = 0;
if (yang_extension_value(ys, "alias", CLIXON_AUTOCLI_NS, &exist, &name) < 0)
goto done;
if (!exist)
name = xml_name(xn);
/* If leaf/leaf-list or presence container, then print line */
if (yang_keyword_get(ys) == Y_LEAF ||
yang_keyword_get(ys) == Y_LEAF_LIST){
if (prepend)
cprintf(cb, "%s", prepend);
if (listkw != AUTOCLI_LISTKW_NONE)
cprintf(cb, "%s ", name);
if ((body = xml_body(xn)) != NULL){
if (index(body, ' '))
cprintf(cb, "\"%s\"", body);
else
cprintf(cb, "%s", body);
}
cprintf(cb, "\n");
goto ok;
}
/* Create prepend variable string */
if ((cbpre = cbuf_new()) == NULL){
clicon_err(OE_PLUGIN, errno, "cbuf_new");
goto done;
}
if (prepend)
cprintf(cbpre, "%s", prepend);
/* If non-presence container && HIDE mode && only child is
* a list, then skip container keyword
* See also yang2cli_container */
if (autocli_compress(h, ys, &compress) < 0)
goto done;
if (!compress)
cprintf(cbpre, "%s ", xml_name(xn));
/* If list then first loop through keys */
if (yang_keyword_get(ys) == Y_LIST){
xe = NULL;
while ((xe = xml_child_each(xn, xe, -1)) != NULL){
if ((match = yang_key_match(ys, xml_name(xe), NULL)) < 0)
goto done;
if (!match)
continue;
if (listkw == AUTOCLI_LISTKW_ALL)
cprintf(cbpre, "%s ", xml_name(xe));
cprintf(cbpre, "%s ", xml_body(xe));
}
}
else if ((yang_keyword_get(ys) == Y_CONTAINER) &&
yang_find(ys, Y_PRESENCE, NULL) != NULL){
/* If presence container, then print as leaf (but continue to children) */
if (prepend)
cprintf(cb, "%s", prepend);
if (listkw != AUTOCLI_LISTKW_NONE)
cprintf(cb, "%s ", xml_name(xn));
if ((body = xml_body(xn)) != NULL){
if (index(body, ' '))
cprintf(cb, "\"%s\"", body);
else
cprintf(cb, "%s", body);
}
cprintf(cb, "\n");
}
/* For lists, print cbpre before its elements */
if (yang_keyword_get(ys) == Y_LIST)
cprintf(cb, "%s\n", cbuf_get(cbpre));
/* Then loop through all other (non-keys) */
xe = NULL;
while ((xe = xml_child_each(xn, xe, -1)) != NULL){
if (yang_keyword_get(ys) == Y_LIST){
if ((match = yang_key_match(ys, xml_name(xe), NULL)) < 0)
goto done;
if (match)
continue; /* Not key itself */
}
if (cli2cbuf(h, cb, xe, cbuf_get(cbpre)) < 0)
goto done;
}
ok:
retval = 0;
done:
if (cbpre)
cbuf_free(cbpre);
return retval;
}
/*! Translate from XML to CLI commands, internal
*
* Howto: join strings and pass them down.
@ -1352,7 +1480,7 @@ cli_pagination(clicon_handle h,
* @param[in] fn Callback to make print function
*/
static int
xml2cli1(clicon_handle h,
cli2file(clicon_handle h,
FILE *f,
cxobj *xn,
char *prepend,
@ -1457,7 +1585,7 @@ xml2cli1(clicon_handle h,
if (match)
continue; /* Not key itself */
}
if (xml2cli1(h, f, xe, cbuf_get(cbpre), fn) < 0)
if (cli2file(h, f, xe, cbuf_get(cbpre), fn) < 0)
goto done;
}
ok:
@ -1480,6 +1608,7 @@ xml2cli1(clicon_handle h,
* @param[in] skiptop 0: Include top object 1: Skip top-object, only children,
* @retval 0 OK
* @retval -1 Error
* @see clixon_cli2cbuf
*/
int
clixon_cli2file(clicon_handle h,
@ -1497,11 +1626,50 @@ clixon_cli2file(clicon_handle h,
if (skiptop){
xc = NULL;
while ((xc = xml_child_each(xn, xc, CX_ELMNT)) != NULL)
if (xml2cli1(h, f, xc, prepend, fn) < 0)
if (cli2file(h, f, xc, prepend, fn) < 0)
goto done;
}
else {
if (xml2cli1(h, f, xn, prepend, fn) < 0)
if (cli2file(h, f, xn, prepend, fn) < 0)
goto done;
}
retval = 0;
done:
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] h Clicon handle
* @param[in] f Output FILE (eg stdout)
* @param[in] xn XML Parse-tree (to translate)
* @param[in] prepend Print this text in front of all commands.
* @param[in] fn File print function (if NULL, use fprintf)
* @param[in] skiptop 0: Include top object 1: Skip top-object, only children,
* @retval 0 OK
* @retval -1 Error
* @see clixon_cli2file
*/
int
clixon_cli2cbuf(clicon_handle h,
cbuf *cb,
cxobj *xn,
char *prepend,
int skiptop)
{
int retval = 1;
cxobj *xc;
if (skiptop){
xc = NULL;
while ((xc = xml_child_each(xn, xc, CX_ELMNT)) != NULL)
if (cli2cbuf(h, cb, xc, prepend) < 0)
goto done;
}
else {
if (cli2cbuf(h, cb, xn, prepend) < 0)
goto done;
}
retval = 0;