Merge branch 'autocli' of https://github.com/shmuelnatan/clixon into shmuelnatan-autocli

This commit is contained in:
Olof hagsand 2021-04-22 20:45:51 +02:00
commit 1c7e52f829
8 changed files with 379 additions and 37 deletions

View file

@ -35,6 +35,9 @@ Expected: June 2021
### Minor features ### Minor features
* Add default network namespace constant: `RESTCONF_NETNS_DEFAULT` with default value "default". * Add default network namespace constant: `RESTCONF_NETNS_DEFAULT` with default value "default".
* CLI: Two new hide variables added (thanks: shmuelnatan)
* hide-database : specifies that a command is not visible in database. This can be useful for setting passwords and not exposing them to users.
* hide-database-auto-completion : specifies that a command is not visible in database and in auto completion. This can be useful for a password that was put in device by super user, not be changed.
## 5.1.0 ## 5.1.0
15 April 2021 15 April 2021

View file

@ -120,6 +120,315 @@ cvec_append(cvec *cvv0,
return cvv2; return cvv2;
} }
/*! x is element and has exactly one child which in turn has none
* @see child_type in clixon_json.c
*/
static int
tleaf(cxobj *x)
{
cxobj *xc;
if (xml_type(x) != CX_ELMNT)
return 0;
if (xml_child_nr_notype(x, CX_ATTR) != 1)
return 0;
/* From here exactly one noattr child, get it */
xc = NULL;
while ((xc = xml_child_each(x, xc, -1)) != NULL)
if (xml_type(xc) != CX_ATTR)
break;
if (xc == NULL)
return -1; /* n/a */
return (xml_child_nr_notype(xc, CX_ATTR) == 0);
}
/*! Print an XML tree structure to an output stream and encode chars "<>&"
*
* @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
cli_xml2file(cxobj *xn,
int level,
int prettyprint,
clicon_output_cb *fn)
{
int retval = -1;
char *name;
char *namespace;
cxobj *xc;
int hasbody;
int haselement;
char *val;
char *encstr = NULL; /* xml encoded string */
char *opext = NULL;
if (xn == NULL)
goto ok;
/* Look for autocli-op defined in clixon-lib.yang */
if (yang_extension_value(xml_spec(xn), "autocli-op", CLIXON_LIB_NS, &opext) < 0) {
goto ok;
}
if ((opext != NULL) && ((strcmp(opext, "hide-database") == 0) || (strcmp(opext, "hide-database-auto-completion") == 0))){
goto ok;
}
name = xml_name(xn);
namespace = xml_prefix(xn);
switch(xml_type(xn)){
case CX_BODY:
if ((val = xml_value(xn)) == NULL) /* incomplete tree */
break;
if (xml_chardata_encode(&encstr, "%s", val) < 0)
goto done;
(*fn)(stdout, "%s", encstr);
break;
case CX_ATTR:
(*fn)(stdout, " ");
if (namespace)
(*fn)(stdout, "%s:", namespace);
(*fn)(stdout, "%s=\"%s\"", name, xml_value(xn));
break;
case CX_ELMNT:
(*fn)(stdout, "%*s<", prettyprint?(level*3):0, "");
if (namespace)
(*fn)(stdout, "%s:", namespace);
(*fn)(stdout, "%s", name);
hasbody = 0;
haselement = 0;
xc = NULL;
/* print attributes only */
while ((xc = xml_child_each(xn, xc, -1)) != NULL) {
switch (xml_type(xc)){
case CX_ATTR:
if (cli_xml2file(xc, level+1, prettyprint, fn) <0)
goto done;
break;
case CX_BODY:
hasbody=1;
break;
case CX_ELMNT:
haselement=1;
break;
default:
break;
}
}
/* Check for special case <a/> instead of <a></a>:
* Ie, no CX_BODY or CX_ELMNT child.
*/
if (hasbody==0 && haselement==0)
(*fn)(stdout, "/>");
else{
(*fn)(stdout, ">");
if (prettyprint && hasbody == 0)
(*fn)(stdout, "\n");
xc = NULL;
while ((xc = xml_child_each(xn, xc, -1)) != NULL) {
if (xml_type(xc) != CX_ATTR)
if (cli_xml2file(xc, level+1, prettyprint, fn) <0)
goto done;
}
if (prettyprint && hasbody==0)
(*fn)(stdout, "%*s", level*3, "");
(*fn)(stdout, "</");
if (namespace)
(*fn)(stdout, "%s:", namespace);
(*fn)(stdout, "%s>", name);
}
if (prettyprint)
(*fn)(stdout, "\n");
break;
default:
break;
}/* switch */
ok:
retval = 0;
done:
if (encstr)
free(encstr);
return retval;
}
/*! Translate XML to a "pseudo-code" textual format using a callback - internal function
* @param[in] xn 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
*/
int
cli_xml2txt(cxobj *xn,
clicon_output_cb *fn,
int level)
{
cxobj *xc = NULL;
int children=0;
int retval = -1;
char *opext = NULL;
if (xn == NULL || fn == NULL){
clicon_err(OE_XML, EINVAL, "xn or fn is NULL");
goto done;
}
/* Look for autocli-op defined in clixon-lib.yang */
if (yang_extension_value(xml_spec(xn), "autocli-op", CLIXON_LIB_NS, &opext) < 0) {
goto ok;
}
if ((opext != NULL) && ((strcmp(opext, "hide-database") == 0) || (strcmp(opext, "hide-database-auto-completion") == 0))){
goto ok;
}
xc = NULL; /* count children (elements and bodies, not attributes) */
while ((xc = xml_child_each(xn, xc, -1)) != NULL)
if (xml_type(xc) == CX_ELMNT || xml_type(xc) == CX_BODY)
children++;
if (!children){ /* If no children print line */
switch (xml_type(xn)){
case CX_BODY:
(*fn)(stdout, "%s;\n", xml_value(xn));
break;
case CX_ELMNT:
(*fn)(stdout, "%*s%s;\n", 4*level, "", xml_name(xn));
break;
default:
break;
}
goto ok;
}
(*fn)(stdout, "%*s", 4*level, "");
(*fn)(stdout, "%s ", xml_name(xn));
if (!tleaf(xn))
(*fn)(stdout, "{\n");
xc = NULL;
while ((xc = xml_child_each(xn, xc, -1)) != NULL){
if (xml_type(xc) == CX_ELMNT || xml_type(xc) == CX_BODY)
if (cli_xml2txt(xc, fn, level+1) < 0)
break;
}
if (!tleaf(xn))
(*fn)(stdout, "%*s}\n", 4*level, "");
ok:
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] xn 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
cli_xml2cli(cxobj *xn,
char *prepend,
enum genmodel_type gt,
clicon_output_cb *fn)
{
int retval = -1;
cxobj *xe = NULL;
cbuf *cbpre = NULL;
yang_stmt *ys;
int match;
char *body;
char *opext = NULL;
if (xml_type(xn)==CX_ATTR)
goto ok;
if ((ys = xml_spec(xn)) == NULL)
goto ok;
/* Look for autocli-op defined in clixon-lib.yang */
if (yang_extension_value(xml_spec(xn), "autocli-op", CLIXON_LIB_NS, &opext) < 0) {
goto ok;
}
if ((opext != NULL) && ((strcmp(opext, "hide-database") == 0) || (strcmp(opext, "hide-database-auto-completion") == 0))){
goto ok;
}
/* 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)
(*fn)(stdout, "%s", prepend);
if (gt == GT_ALL || gt == GT_VARS || gt == GT_HIDE)
(*fn)(stdout, "%s ", xml_name(xn));
if ((body = xml_body(xn)) != NULL){
if (index(body, ' '))
(*fn)(stdout, "\"%s\"", body);
else
(*fn)(stdout, "%s", body);
}
(*fn)(stdout, "\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 (yang_container_cli_hide(ys, gt) == 0)
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))) < 0)
goto done;
if (!match)
continue;
if (gt == GT_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)
(*fn)(stdout, "%s", prepend);
if (gt == GT_ALL || gt == GT_VARS || gt == GT_HIDE)
(*fn)(stdout, "%s ", xml_name(xn));
if ((body = xml_body(xn)) != NULL){
if (index(body, ' '))
(*fn)(stdout, "\"%s\"", body);
else
(*fn)(stdout, "%s", body);
}
(*fn)(stdout, "\n");
}
/* 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))) < 0)
goto done;
if (match){
(*fn)(stdout, "%s\n", cbuf_get(cbpre));
continue; /* Not key itself */
}
}
if (cli_xml2cli(xe, cbuf_get(cbpre), gt, fn) < 0)
goto done;
}
ok:
retval = 0;
done:
if (cbpre)
cbuf_free(cbpre);
return retval;
}
/*! Enter a CLI edit mode /*! Enter a CLI edit mode
* @param[in] h CLICON handle * @param[in] h CLICON handle
* @param[in] cvv Vector of variables from CLIgen command-line * @param[in] cvv Vector of variables from CLIgen command-line
@ -413,10 +722,10 @@ cli_auto_show(clicon_handle h,
switch (format){ switch (format){
case FORMAT_XML: case FORMAT_XML:
if (isroot) if (isroot)
clicon_xml2file(stdout, xp, 0, pretty); cli_xml2file(xp, 0, pretty, fprintf);
else{ else{
while ((xc = xml_child_each(xp, xc, CX_ELMNT)) != NULL) while ((xc = xml_child_each(xp, xc, CX_ELMNT)) != NULL)
clicon_xml2file(stdout, xc, 0, pretty); cli_xml2file(xc, 0, pretty, fprintf);
} }
fprintf(stdout, "\n"); fprintf(stdout, "\n");
break; break;
@ -431,19 +740,19 @@ cli_auto_show(clicon_handle h,
break; break;
case FORMAT_TEXT: case FORMAT_TEXT:
if (isroot) if (isroot)
xml2txt_cb(stdout, xp, cligen_output); /* tree-formed text */ cli_xml2txt(xp, cligen_output, 0); /* tree-formed text */
else else
while ((xc = xml_child_each(xp, xc, CX_ELMNT)) != NULL) while ((xc = xml_child_each(xp, xc, CX_ELMNT)) != NULL)
xml2txt_cb(stdout, xc, cligen_output); /* tree-formed text */ cli_xml2txt(xc, cligen_output, 0); /* 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;
if (isroot) if (isroot)
xml2cli_cb(stdout, xp, prefix, gt, cligen_output); /* cli syntax */ cli_xml2cli(xp, prefix, gt, cligen_output); /* cli syntax */
else else
while ((xc = xml_child_each(xp, xc, CX_ELMNT)) != NULL) while ((xc = xml_child_each(xp, xc, CX_ELMNT)) != NULL)
xml2cli_cb(stdout, xc, prefix, gt, cligen_output); /* cli syntax */ cli_xml2cli(xc, prefix, gt, cligen_output); /* cli syntax */
break; break;
case FORMAT_NETCONF: case FORMAT_NETCONF:
fprintf(stdout, "<rpc xmlns=\"%s\"><edit-config><target><candidate/></target><config>", fprintf(stdout, "<rpc xmlns=\"%s\"><edit-config><target><candidate/></target><config>",
@ -451,10 +760,10 @@ cli_auto_show(clicon_handle h,
if (pretty) if (pretty)
fprintf(stdout, "\n"); fprintf(stdout, "\n");
if (isroot) if (isroot)
clicon_xml2file(stdout, xp, 2, pretty); cli_xml2file(xp, 2, pretty, fprintf);
else else
while ((xc = xml_child_each(xp, xc, CX_ELMNT)) != NULL) while ((xc = xml_child_each(xp, xc, CX_ELMNT)) != NULL)
clicon_xml2file(stdout, xc, 2, pretty); cli_xml2file(xc, 2, pretty, fprintf);
fprintf(stdout, "</config></edit-config></rpc>]]>]]>\n"); fprintf(stdout, "</config></edit-config></rpc>]]>]]>\n");
break; break;
} /* switch */ } /* switch */

View file

@ -119,7 +119,14 @@ cli_expand_var_generate(clicon_handle h,
cbuf *cb) cbuf *cb)
{ {
int retval = -1; int retval = -1;
char *api_path_fmt = NULL; char *api_path_fmt = NULL, *opext = NULL;
if (yang_extension_value(ys, "autocli-op", CLIXON_LIB_NS, &opext) < 0)
goto done;
if (opext && strcmp(opext, "hide-database") == 0) {
retval = 1;
goto done;
}
if (yang2api_path_fmt(ys, 1, &api_path_fmt) < 0) if (yang2api_path_fmt(ys, 1, &api_path_fmt) < 0)
goto done; goto done;
@ -574,7 +581,7 @@ yang2cli_var(clicon_handle h,
uint8_t fraction_digits = 0; uint8_t fraction_digits = 0;
enum cv_type cvtype; enum cv_type cvtype;
int options = 0; int options = 0;
int completionp; int completionp, result;
char *type; char *type;
if ((patterns = cvec_new(0)) == NULL){ if ((patterns = cvec_new(0)) == NULL){
@ -599,10 +606,12 @@ yang2cli_var(clicon_handle h,
if (yang2cli_var_union(h, ys, origtype, yrestype, helptext, cb) < 0) if (yang2cli_var_union(h, ys, origtype, yrestype, helptext, cb) < 0)
goto done; goto done;
if (clicon_cli_genmodel_completion(h)){ if (clicon_cli_genmodel_completion(h)){
if (cli_expand_var_generate(h, ys, cvtype, result = cli_expand_var_generate(h, ys, cvtype,
options, fraction_digits, options, fraction_digits,
cb) < 0) cb);
if (result < 0)
goto done; goto done;
if (result == 0)
yang2cli_helptext(cb, helptext); yang2cli_helptext(cb, helptext);
} }
cprintf(cb, ")"); cprintf(cb, ")");
@ -622,10 +631,12 @@ yang2cli_var(clicon_handle h,
options, cvv, patterns, fraction_digits, cb)) < 0) options, cvv, patterns, fraction_digits, cb)) < 0)
goto done; goto done;
if (completionp){ if (completionp){
if (cli_expand_var_generate(h, ys, cvtype, result = cli_expand_var_generate(h, ys, cvtype,
options, fraction_digits, options, fraction_digits,
cb) < 0) cb);
if (result < 0)
goto done; goto done;
if (result == 0)
yang2cli_helptext(cb, helptext); yang2cli_helptext(cb, helptext);
cprintf(cb, ")"); cprintf(cb, ")");
} }
@ -688,6 +699,10 @@ yang2cli_leaf(clicon_handle h,
cprintf(cb, ",hide{"); cprintf(cb, ",hide{");
extralevel = 1; extralevel = 1;
} }
if (opext && strcmp(opext, "hide-database-auto-completion") == 0){
cprintf(cb, ",hide-database-auto-completion{");
extralevel = 1;
}
if (yang2cli_var(h, ys, helptext, cb) < 0) if (yang2cli_var(h, ys, helptext, cb) < 0)
goto done; goto done;
} }
@ -695,6 +710,9 @@ yang2cli_leaf(clicon_handle h,
if (opext && strcmp(opext, "hide") == 0){ if (opext && strcmp(opext, "hide") == 0){
cprintf(cb, ",hide"); cprintf(cb, ",hide");
} }
if (opext && strcmp(opext, "hide-database-auto-completion") == 0){
cprintf(cb, ",hide-database-auto-completion");
}
} }
} }
else{ else{
@ -767,6 +785,9 @@ yang2cli_container(clicon_handle h,
if (opext != NULL && strcmp(opext, "hide") == 0){ if (opext != NULL && strcmp(opext, "hide") == 0){
cprintf(cb, ",hide"); cprintf(cb, ",hide");
} }
if (opext != NULL && strcmp(opext, "hide-database-auto-completion") == 0){
cprintf(cb, ",hide-database-auto-completion");
}
cprintf(cb, ";{\n"); cprintf(cb, ";{\n");
} }
@ -815,13 +836,6 @@ yang2cli_list(clicon_handle h,
char *opext = NULL; char *opext = NULL;
cprintf(cb, "%*s%s", level*3, "", yang_argument_get(ys)); cprintf(cb, "%*s%s", level*3, "", yang_argument_get(ys));
/* Look for autocli-op defined in clixon-lib.yang */
if (yang_extension_value(ys, "autocli-op", CLIXON_LIB_NS, &opext) < 0)
goto done;
if (opext != NULL && strcmp(opext, "hide") == 0){
cprintf(cb, ",hide");
extralevel = 1;
}
if ((yd = yang_find(ys, Y_DESCRIPTION, NULL)) != NULL){ if ((yd = yang_find(ys, Y_DESCRIPTION, NULL)) != NULL){
if ((helptext = strdup(yang_argument_get(yd))) == NULL){ if ((helptext = strdup(yang_argument_get(yd))) == NULL){
clicon_err(OE_UNIX, errno, "strdup"); clicon_err(OE_UNIX, errno, "strdup");
@ -831,6 +845,17 @@ yang2cli_list(clicon_handle h,
*s = '\0'; *s = '\0';
yang2cli_helptext(cb, helptext); yang2cli_helptext(cb, helptext);
} }
/* Look for autocli-op defined in clixon-lib.yang */
if (yang_extension_value(ys, "autocli-op", CLIXON_LIB_NS, &opext) < 0)
goto done;
if (opext != NULL && strcmp(opext, "hide") == 0){
cprintf(cb, ",hide");
extralevel = 1;
}
if (opext != NULL && strcmp(opext, "hide-database-auto-completion") == 0){
cprintf(cb, ",hide-database-auto-completion");
extralevel = 1;
}
/* Loop over all key variables */ /* Loop over all key variables */
cvk = yang_cvec_get(ys); /* Use Y_LIST cache, see ys_populate_list() */ cvk = yang_cvec_get(ys); /* Use Y_LIST cache, see ys_populate_list() */
cvi = NULL; cvi = NULL;

View file

@ -476,7 +476,7 @@ 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_cb(stdout, xc, 0, 1, cligen_output); cli_xml2file(xc, 0, 1, cligen_output);
break; break;
case FORMAT_JSON: case FORMAT_JSON:
xml2json_cb(stdout, xt, 1, cligen_output); xml2json_cb(stdout, xt, 1, cligen_output);
@ -484,7 +484,7 @@ cli_show_config1(clicon_handle h,
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_cb(stdout, xc, cligen_output); /* tree-formed text */ cli_xml2txt(xc, cligen_output, 0); /* tree-formed text */
break; break;
case FORMAT_CLI: case FORMAT_CLI:
/* get CLI generatade mode: VARS|ALL */ /* get CLI generatade mode: VARS|ALL */
@ -492,14 +492,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_cb(stdout, xc, prefix, gt, cligen_output); /* cli syntax */ cli_xml2cli(xc, prefix, gt, cligen_output); /* cli syntax */
break; break;
case FORMAT_NETCONF: case FORMAT_NETCONF:
cligen_output(stdout, "<rpc xmlns=\"%s\"><edit-config><target><candidate/></target><config>\n", cligen_output(stdout, "<rpc xmlns=\"%s\"><edit-config><target><candidate/></target><config>\n",
NETCONF_BASE_NAMESPACE); NETCONF_BASE_NAMESPACE);
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_cb(stdout, xc, 2, 1, cligen_output); cli_xml2file(xc, 2, 1, cligen_output);
cligen_output(stdout, "</config></edit-config></rpc>]]>]]>\n"); cligen_output(stdout, "</config></edit-config></rpc>]]>]]>\n");
break; break;
} }
@ -623,7 +623,7 @@ show_conf_xpath(clicon_handle h,
if (xpath_vec(xt, nsc, "%s", &xv, &xlen, xpath) < 0) if (xpath_vec(xt, nsc, "%s", &xv, &xlen, xpath) < 0)
goto done; goto done;
for (i=0; i<xlen; i++) for (i=0; i<xlen; i++)
xml_print(stdout, xv[i]); cli_xml2file(xv[i], 0, 1, fprintf);
retval = 0; retval = 0;
done: done:
@ -743,24 +743,24 @@ cli_show_auto1(clicon_handle h,
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_cb(stdout, xp, prefix, gt, cligen_output); /* cli syntax */ cli_xml2cli(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");
clicon_xml2file(stdout, xp, 2, 1); cli_xml2file(xp, 2, 1, fprintf);
fprintf(stdout, "</config></edit-config></rpc>]]>]]>\n"); fprintf(stdout, "</config></edit-config></rpc>]]>]]>\n");
break; break;
default: default:
for (; i < xml_child_nr(xml_parent(xp)) ; ++i, xp_helper = xml_child_i(xml_parent(xp), i)) { for (; i < xml_child_nr(xml_parent(xp)) ; ++i, xp_helper = xml_child_i(xml_parent(xp), i)) {
switch (format){ switch (format){
case FORMAT_XML: case FORMAT_XML:
clicon_xml2file(stdout, xp_helper, 0, 1); cli_xml2file(xp_helper, 0, 1, fprintf);
break; break;
case FORMAT_JSON: case FORMAT_JSON:
xml2json_cb(stdout, xp_helper, 1, cligen_output); xml2json_cb(stdout, xp_helper, 1, cligen_output);
break; break;
case FORMAT_TEXT: case FORMAT_TEXT:
xml2txt_cb(stdout, xp_helper, cligen_output); /* tree-formed text */ cli_xml2txt(xp_helper, cligen_output, 0); /* tree-formed text */
break; break;
default: /* see cli_show_config() */ default: /* see cli_show_config() */
break; break;

View file

@ -116,6 +116,9 @@ int cli_help(clicon_handle h, cvec *vars, cvec *argv);
/* In cli_show.c */ /* In cli_show.c */
int expand_dbvar(void *h, char *name, cvec *cvv, cvec *argv, int expand_dbvar(void *h, char *name, cvec *cvv, cvec *argv,
cvec *commands, cvec *helptexts); cvec *commands, cvec *helptexts);
int cli_xml2file (cxobj *xn, int level, int prettyprint, clicon_output_cb *fn);
int cli_xml2txt(cxobj *xn, clicon_output_cb *fn, int level);
int cli_xml2cli(cxobj *xn, char *prepend, enum genmodel_type gt, clicon_output_cb *fn);
/* cli_show.c: CLIgen new vector arg callbacks */ /* cli_show.c: CLIgen new vector arg callbacks */
int show_yang(clicon_handle h, cvec *vars, cvec *argv); int show_yang(clicon_handle h, cvec *vars, cvec *argv);

View file

@ -171,13 +171,13 @@ static int
flogtime(FILE *f) flogtime(FILE *f)
{ {
struct timeval tv; struct timeval tv;
struct tm tm; struct tm *tm;
gettimeofday(&tv, NULL); gettimeofday(&tv, NULL);
localtime_r((time_t*)&tv.tv_sec, &tm); tm = localtime((time_t*)&tv.tv_sec);
fprintf(f, "%s %2d %02d:%02d:%02d: ", fprintf(f, "%s %2d %02d:%02d:%02d: ",
mon2name(tm.tm_mon), tm.tm_mday, mon2name(tm->tm_mon), tm->tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec); tm->tm_hour, tm->tm_min, tm->tm_sec);
return 0; return 0;
} }

View file

@ -103,7 +103,9 @@ module clixon-lib {
this point in the YANG tree for the automated generated CLI. this point in the YANG tree for the automated generated CLI.
Note that this extension is only used in clixon_cli. Note that this extension is only used in clixon_cli.
Operations is expected to be extended, but the following operations are defined: Operations is expected to be extended, but the following operations are defined:
- hide This command is active but not shown by ? or TAB"; - hide This command is active but not shown by ? or TAB (meaning, it hides the auto-completion of commands)
- hide-database This command hides the database
- hide-database-auto-completion This command hides the database and the auto completion (meaning, this command acts as both commands above)";
argument cliop; argument cliop;
} }
rpc debug { rpc debug {