* Renamed clixon-clispec.yang to clixon-autocli.yang
* First version of clixon-autocli.yang semantics * Default rules for module exclusion, list-keywords, completion, treeref-state * Specialized rules for compress and exclusion of modules * See [autocli documentation](https://clixon-docs.readthedocs.io/en/latest/cli.html#autocli) * Obsoleted and moved autocli config options from clixon-config.yang to clixon-autocli.yang as follows: * `CLICON_CLI_GENMODEL`, use: `autocli/module-default=false` instead * Removed `clicon_cli_genmodel()` * `CLICON_CLI_GENMODEL_TYPE`, use `autocli/list-keyword-default` and compress rules instead) * Removed `clicon_cli_genmodel_type()` * `CLICON_CLI_GENMODEL_COMPLETION`, use `autocli/completion-default` instead * Removed `clicon_cli_genmodel_completion()` * `CLICON_CLI_AUTOCLI_EXCLUDE`, use `autocli/rule/operation=exclude` instead * `CLICON_CLI_MODEL_TREENAME`, use constant `AUTOCLI_TREENAME` instead * Removed `clicon_cli_model_treename()` * New YANG functions: yang_single_child_type, yang_find_namespace_by_prefix, yang_str2key * Changed return values of yang_find_prefix_by_namespace * Merged `cli_cli2xml()` into `cli2xml()`
This commit is contained in:
parent
dec05e2cae
commit
081e6871b3
45 changed files with 1804 additions and 900 deletions
|
|
@ -43,8 +43,11 @@
|
|||
* YANG generate CLI
|
||||
|
||||
* A special tree called @datamodel is generated by the yang2cli function.
|
||||
* This tree contains generated CLIgen syntax for all loaded YANG modules, except the ones given by
|
||||
* CLICON_CLI_AUTOCLI_EXCLUDE
|
||||
* This tree contains generated CLIgen syntax for loaded YANG modules, according to the
|
||||
* include/exclude logic in clixon-autocli.yang defined by the following fields:
|
||||
* module-default
|
||||
* rule/module-name
|
||||
* rule/operation=exclude|include
|
||||
* The @datamodel tree can be used using the CLIgen "tree reference" functionality as described in
|
||||
* the cligen tutorial Secion 2.7.
|
||||
* The tree can be modified by removing labels.
|
||||
|
|
@ -89,16 +92,18 @@ You can see which CLISPEC it generates via clixon_cli -D 2:
|
|||
#include <fcntl.h>
|
||||
#include <syslog.h>
|
||||
#include <signal.h>
|
||||
#include <assert.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
/* cligen */
|
||||
#include <cligen/cligen.h>
|
||||
|
||||
/* Clicon */
|
||||
/* libclixon */
|
||||
#include <clixon/clixon.h>
|
||||
|
||||
#include "clixon_cli_api.h"
|
||||
#include "cli_plugin.h"
|
||||
#include "cli_autocli.h"
|
||||
#include "cli_generate.h"
|
||||
|
||||
/*
|
||||
|
|
@ -370,8 +375,7 @@ yang2cli_var_pattern(clicon_handle h,
|
|||
}
|
||||
|
||||
/* Forward */
|
||||
static int yang2cli_stmt(clicon_handle h, yang_stmt *ys, genmodel_type gt,
|
||||
int level, cbuf *cb);
|
||||
static int yang2cli_stmt(clicon_handle h, yang_stmt *ys, int level, cbuf *cb);
|
||||
|
||||
static int yang2cli_var_union(clicon_handle h, yang_stmt *ys, char *origtype,
|
||||
yang_stmt *ytype, char *helptext, cbuf *cb);
|
||||
|
|
@ -592,13 +596,14 @@ yang2cli_var_leafref(clicon_handle h,
|
|||
*/
|
||||
type = yrestype?yang_argument_get(yrestype):NULL;
|
||||
cvtypestr = cv_type2str(cvtype);
|
||||
if (type)
|
||||
completionp = clicon_cli_genmodel_completion(h) &&
|
||||
strcmp(type, "enumeration") != 0 &&
|
||||
if (autocli_completion(h, &completionp) < 0)
|
||||
goto done;
|
||||
if (type && completionp){
|
||||
completionp = strcmp(type, "enumeration") != 0 &&
|
||||
strcmp(type, "identityref") != 0 &&
|
||||
strcmp(type, "bits") != 0;
|
||||
else
|
||||
completionp = clicon_cli_genmodel_completion(h);
|
||||
}
|
||||
|
||||
if (completionp)
|
||||
cprintf(cb, "(");
|
||||
if (yang2cli_var_sub(h, ys, yrestype, helptext, cvtype,
|
||||
|
|
@ -619,11 +624,11 @@ yang2cli_var_leafref(clicon_handle h,
|
|||
}
|
||||
|
||||
/*! Generate CLI code for Yang leaf statement to CLIgen variable
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] ys Yang statement of original leaf
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] ys Yang statement of original leaf
|
||||
* @param[in] yreferred Yang statement of referred node for type (leafref)
|
||||
* @param[in] helptext CLI help text
|
||||
* @param[out] cb Buffer where cligen code is written
|
||||
* @param[in] helptext CLI help text
|
||||
* @param[out] cb Buffer where cligen code is written
|
||||
*
|
||||
* Make a type lookup and complete a cligen variable expression such as <a:string>.
|
||||
* One complication is yang union, that needs a recursion since it consists of
|
||||
|
|
@ -653,6 +658,7 @@ yang2cli_var(clicon_handle h,
|
|||
char *cvtypestr;
|
||||
int options = 0;
|
||||
int result;
|
||||
int completionp;
|
||||
|
||||
if ((patterns = cvec_new(0)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cvec_new");
|
||||
|
|
@ -675,7 +681,9 @@ yang2cli_var(clicon_handle h,
|
|||
cprintf(cb, "(");
|
||||
if (yang2cli_var_union(h, ys, origtype, yrestype, helptext, cb) < 0)
|
||||
goto done;
|
||||
if (clicon_cli_genmodel_completion(h)){
|
||||
if (autocli_completion(h, &completionp) < 0)
|
||||
goto done;
|
||||
if (completionp){
|
||||
if ((result = cli_expand_var_generate(h, ys, cvtypestr,
|
||||
options, fraction_digits,cb)) < 0)
|
||||
goto done;
|
||||
|
|
@ -702,7 +710,7 @@ yang2cli_var(clicon_handle h,
|
|||
if (yref == NULL){
|
||||
/* Give up: use yreferred
|
||||
*/
|
||||
if (yang2cli_var_leafref(h, ys, yrestype, helptext, cvtype, options,
|
||||
if (yang2cli_var_leafref(h, ys, yrestype, helptext, cvtype, options,
|
||||
cvv, patterns, fraction_digits, cb) < 0)
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -735,7 +743,6 @@ yang2cli_var(clicon_handle h,
|
|||
/*! Generate CLI code for Yang leaf statement
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] ys Yang statement
|
||||
* @param[in] gt CLI Generate style
|
||||
* @param[in] level Indentation level
|
||||
* @param[in] callback If set, include a "; cli_set()" callback, otherwise not
|
||||
* @param[in] key_leaf Is leaf in a key in a list module
|
||||
|
|
@ -744,7 +751,6 @@ yang2cli_var(clicon_handle h,
|
|||
static int
|
||||
yang2cli_leaf(clicon_handle h,
|
||||
yang_stmt *ys,
|
||||
genmodel_type gt,
|
||||
int level,
|
||||
int callback,
|
||||
int key_leaf,
|
||||
|
|
@ -756,6 +762,7 @@ yang2cli_leaf(clicon_handle h,
|
|||
char *s;
|
||||
char *opext = NULL;
|
||||
int extralevel = 0;
|
||||
autocli_listkw_t listkw;
|
||||
|
||||
/* description */
|
||||
if ((yd = yang_find(ys, Y_DESCRIPTION, NULL)) != NULL){
|
||||
|
|
@ -770,7 +777,10 @@ yang2cli_leaf(clicon_handle h,
|
|||
/* Look for autocli-op defined in clixon-lib.yang */
|
||||
if (yang_extension_value(ys, "autocli-op", CLIXON_LIB_NS, NULL, &opext) < 0)
|
||||
goto done;
|
||||
if (gt == GT_VARS || gt == GT_ALL || gt == GT_HIDE || gt == GT_OC_COMPRESS){
|
||||
if (autocli_list_keyword(h, &listkw) < 0)
|
||||
goto done;
|
||||
if (listkw == AUTOCLI_LISTKW_ALL ||
|
||||
(!key_leaf && listkw == AUTOCLI_LISTKW_NOKEY)){
|
||||
cprintf(cb, "%s", yang_argument_get(ys));
|
||||
yang2cli_helptext(cb, helptext);
|
||||
cprintf(cb, " ");
|
||||
|
|
@ -806,14 +816,12 @@ yang2cli_leaf(clicon_handle h,
|
|||
/*! Generate CLI code for Yang container statement
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] ys Yang statement
|
||||
* @param[in] gt CLI Generate style
|
||||
* @param[in] level Indentation level
|
||||
* @param[out] cb Buffer where cligen code is written
|
||||
*/
|
||||
static int
|
||||
yang2cli_container(clicon_handle h,
|
||||
yang_stmt *ys,
|
||||
genmodel_type gt,
|
||||
int level,
|
||||
cbuf *cb)
|
||||
{
|
||||
|
|
@ -822,28 +830,20 @@ yang2cli_container(clicon_handle h,
|
|||
int retval = -1;
|
||||
char *helptext = NULL;
|
||||
char *s;
|
||||
int hide = 0;
|
||||
int compress = 0;
|
||||
int hide_oc = 0;
|
||||
int isoc = 0;
|
||||
char *opext = NULL;
|
||||
yang_stmt *ymod = NULL;
|
||||
|
||||
if (ys_real_module(ys, &ymod) < 0)
|
||||
goto done;
|
||||
/* Hide container "config" if openconfig and OC_COMPRESS */
|
||||
if (strcmp(yang_argument_get(ys), "config") == 0){
|
||||
if (yang_extension_value(ymod, "openconfig-version", "http://openconfig.net/yang/openconfig-ext", &isoc, NULL) < 0)
|
||||
goto done;
|
||||
if (isoc &&
|
||||
gt == GT_OC_COMPRESS)
|
||||
hide_oc = 1;
|
||||
}
|
||||
|
||||
/* If non-presence container && HIDE mode && only child is
|
||||
* a list, then skip container keyword
|
||||
* See also xml2cli
|
||||
*/
|
||||
if ((hide = yang_container_cli_hide(ys, gt)) == 0 && hide_oc == 0){
|
||||
if (autocli_compress(h, ys, &compress) < 0)
|
||||
goto done;
|
||||
if (!compress && hide_oc == 0){
|
||||
cprintf(cb, "%*s%s", level*3, "", yang_argument_get(ys));
|
||||
if ((yd = yang_find(ys, Y_DESCRIPTION, NULL)) != NULL){
|
||||
if ((helptext = strdup(yang_argument_get(yd))) == NULL){
|
||||
|
|
@ -871,9 +871,9 @@ yang2cli_container(clicon_handle h,
|
|||
|
||||
yc = NULL;
|
||||
while ((yc = yn_each(ys, yc)) != NULL)
|
||||
if (yang2cli_stmt(h, yc, gt, level+1, cb) < 0)
|
||||
if (yang2cli_stmt(h, yc, level+1, cb) < 0)
|
||||
goto done;
|
||||
if (hide == 0 && hide_oc == 0)
|
||||
if (!compress && hide_oc == 0)
|
||||
cprintf(cb, "%*s}\n", level*3, "");
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
@ -885,14 +885,12 @@ yang2cli_container(clicon_handle h,
|
|||
/*! Generate CLI code for Yang list statement
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] ys Yang statement
|
||||
* @param[in] gt CLI Generate style
|
||||
* @param[in] level Indentation level
|
||||
* @param[out] cb Buffer where cligen code is written
|
||||
*/
|
||||
static int
|
||||
yang2cli_list(clicon_handle h,
|
||||
yang_stmt *ys,
|
||||
genmodel_type gt,
|
||||
int level,
|
||||
cbuf *cb)
|
||||
{
|
||||
|
|
@ -949,8 +947,10 @@ yang2cli_list(clicon_handle h,
|
|||
cprintf(cb, "{\n");
|
||||
}
|
||||
if (yang2cli_leaf(h, yleaf,
|
||||
(gt==GT_VARS||gt==GT_HIDE||gt==GT_OC_COMPRESS)?GT_NONE:gt, level+1,
|
||||
last_key, 1, cb) < 0)
|
||||
level+1,
|
||||
last_key,
|
||||
1, /* key_leaf */
|
||||
cb) < 0)
|
||||
goto done;
|
||||
}
|
||||
cprintf(cb, "{\n");
|
||||
|
|
@ -967,7 +967,7 @@ yang2cli_list(clicon_handle h,
|
|||
}
|
||||
if (cvi != NULL)
|
||||
continue;
|
||||
if (yang2cli_stmt(h, yc, gt, level+1, cb) < 0)
|
||||
if (yang2cli_stmt(h, yc, level+1, cb) < 0)
|
||||
goto done;
|
||||
}
|
||||
cprintf(cb, "%*s}\n", level*3, "");
|
||||
|
|
@ -984,7 +984,6 @@ yang2cli_list(clicon_handle h,
|
|||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] ys Yang statement
|
||||
* @param[in] gt CLI Generate style
|
||||
* @param[in] level Indentation level
|
||||
* @param[out] cb Buffer where cligen code is written
|
||||
@example
|
||||
|
|
@ -999,7 +998,6 @@ yang2cli_list(clicon_handle h,
|
|||
static int
|
||||
yang2cli_choice(clicon_handle h,
|
||||
yang_stmt *ys,
|
||||
genmodel_type gt,
|
||||
int level,
|
||||
cbuf *cb)
|
||||
{
|
||||
|
|
@ -1010,7 +1008,7 @@ yang2cli_choice(clicon_handle h,
|
|||
while ((yc = yn_each(ys, yc)) != NULL) {
|
||||
switch (yang_keyword_get(yc)){
|
||||
case Y_CASE:
|
||||
if (yang2cli_stmt(h, yc, gt, level+2, cb) < 0)
|
||||
if (yang2cli_stmt(h, yc, level+2, cb) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case Y_CONTAINER:
|
||||
|
|
@ -1018,7 +1016,7 @@ yang2cli_choice(clicon_handle h,
|
|||
case Y_LEAF_LIST:
|
||||
case Y_LIST:
|
||||
default:
|
||||
if (yang2cli_stmt(h, yc, gt, level+1, cb) < 0)
|
||||
if (yang2cli_stmt(h, yc, level+1, cb) < 0)
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1031,48 +1029,52 @@ yang2cli_choice(clicon_handle h,
|
|||
/*! Generate CLI code for Yang statement
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] ys Yang statement
|
||||
* @param[in] gt CLI Generate style
|
||||
* @param[in] level Indentation level
|
||||
* @param[out] cb Buffer where cligen code is written
|
||||
*/
|
||||
static int
|
||||
yang2cli_stmt(clicon_handle h,
|
||||
yang_stmt *ys,
|
||||
genmodel_type gt,
|
||||
int level,
|
||||
cbuf *cb)
|
||||
{
|
||||
yang_stmt *yc;
|
||||
int retval = -1;
|
||||
|
||||
switch (yang_keyword_get(ys)){
|
||||
case Y_CONTAINER:
|
||||
if (yang2cli_container(h, ys, gt, level, cb) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case Y_LIST:
|
||||
if (yang2cli_list(h, ys, gt, level, cb) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case Y_CHOICE:
|
||||
if (yang2cli_choice(h, ys, gt, level, cb) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case Y_LEAF_LIST:
|
||||
case Y_LEAF:
|
||||
if (yang2cli_leaf(h, ys, gt, level, 1, 0, cb) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case Y_CASE:
|
||||
case Y_SUBMODULE:
|
||||
case Y_MODULE:
|
||||
yc = NULL;
|
||||
while ((yc = yn_each(ys, yc)) != NULL)
|
||||
if (yang2cli_stmt(h, yc, gt, level+1, cb) < 0)
|
||||
yang_stmt *yc;
|
||||
int retval = -1;
|
||||
int treeref_state = 0;
|
||||
|
||||
/* Only produce autocli for YANG non-config only if autocli-treeref-state is true */
|
||||
if (autocli_treeref_state(h, &treeref_state) < 0)
|
||||
goto done;
|
||||
if (treeref_state || yang_config(ys)){
|
||||
switch (yang_keyword_get(ys)){
|
||||
case Y_CONTAINER:
|
||||
if (yang2cli_container(h, ys, level, cb) < 0)
|
||||
goto done;
|
||||
break;
|
||||
default: /* skip */
|
||||
break;
|
||||
break;
|
||||
case Y_LIST:
|
||||
if (yang2cli_list(h, ys, level, cb) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case Y_CHOICE:
|
||||
if (yang2cli_choice(h, ys, level, cb) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case Y_LEAF_LIST:
|
||||
case Y_LEAF:
|
||||
if (yang2cli_leaf(h, ys, level, 1, 0, cb) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case Y_CASE:
|
||||
case Y_SUBMODULE:
|
||||
case Y_MODULE:
|
||||
yc = NULL;
|
||||
while ((yc = yn_each(ys, yc)) != NULL)
|
||||
if (yang2cli_stmt(h, yc, level+1, cb) < 0)
|
||||
goto done;
|
||||
break;
|
||||
default: /* skip */
|
||||
break;
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
@ -1107,13 +1109,16 @@ cvec_add_name(cvec *cvv,
|
|||
|
||||
/*! Recursive post processing of generated cligen parsetree: populate with co_cvec labels
|
||||
*
|
||||
|
||||
* This function adds labels to the generated CLIgen tree using YANG as follows:
|
||||
* These labels can be filtered when applying them with the @treeref, @add:<label> syntax.
|
||||
* (terminal entry means eg "a ;" where ; is an "empty" child of "a" representing a terminal)
|
||||
* 1. Add "termfirstkeys" label on terminal entries of LIST keys, except last
|
||||
* 2. Add "termlist" label on terminal entries of LIST
|
||||
* 3. Add "termleaf" label on terminal entries of non-empty LEAF/LEAF_LISTs
|
||||
* 4. Add "leafvar" label on nodes which are children of non-key LEAFs, eg "a <a>" -> "a <a>,leaf"
|
||||
* 5. Add "nonconfig" label on nodes which have YANG "config false" as children
|
||||
* NYI 6. Add "config" label on nodes which have no config false children recursively
|
||||
*
|
||||
* Then, later, labels can be grouped into specific usages:
|
||||
* - config: @remove:termfirstkeys,@remote:termlist,@remove:termleaf,@remove:nonconfig,
|
||||
|
|
@ -1124,39 +1129,46 @@ cvec_add_name(cvec *cvv,
|
|||
* @param[in] cop Parent cliegn object (if any)
|
||||
* @param[in] pt CLIgen parse-tree (generated syntax)
|
||||
* @param[in] i0 Offset into pt
|
||||
* @param[in] y YANG node of "pt"
|
||||
* @param[in] yp YANG parent node of "pt"
|
||||
* @param[in] ykey Special case, If y is list, yc can be a leaf key
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @note Top-level lookup is O(n^2) since:
|
||||
* for y in modules
|
||||
* for co in top-level commands
|
||||
* if yc = find(y,co)=NULL continue; <----
|
||||
* Also adds an empty node under LIST which is a kludge, it cannot be expressed in the CLIgen syntax
|
||||
*/
|
||||
static int
|
||||
yang2cli_post(clicon_handle h,
|
||||
cg_obj *cop,
|
||||
parse_tree *pt,
|
||||
int i0,
|
||||
yang_stmt *y,
|
||||
yang_stmt *yp,
|
||||
yang_stmt *ykey)
|
||||
{
|
||||
int retval = -1;
|
||||
cg_obj *co;
|
||||
int i;
|
||||
yang_stmt *yc;
|
||||
int yciskey;
|
||||
int ycislastkey;
|
||||
enum rfc_6020 ykeyword;
|
||||
cg_obj *co;
|
||||
int i;
|
||||
int j;
|
||||
yang_stmt *yc;
|
||||
int yciskey;
|
||||
int ycislastkey;
|
||||
enum rfc_6020 ypkeyword;
|
||||
cg_obj *coj;
|
||||
|
||||
ykeyword = yang_keyword_get(y);
|
||||
ypkeyword = yang_keyword_get(yp);
|
||||
for (i = i0; i<pt_len_get(pt); i++){
|
||||
if ((co = pt_vec_i_get(pt, i)) == NULL){
|
||||
clicon_err(OE_YANG, 0, "Empty object in parsetreelist"); /* shouldnt happen */
|
||||
goto done;
|
||||
}
|
||||
if (co->co_type == CO_EMPTY){
|
||||
if (ykeyword == Y_LIST){
|
||||
if (ypkeyword == Y_LIST){
|
||||
if (ykey){
|
||||
/* key, list has a <cr> which is marked as "show" */
|
||||
ycislastkey = 0;
|
||||
yang_key_match(y, yang_argument_get(ykey), &ycislastkey);
|
||||
yang_key_match(yp, yang_argument_get(ykey), &ycislastkey);
|
||||
if (!ycislastkey || (cop && cop->co_type==CO_COMMAND))
|
||||
if ((co->co_cvec = cvec_add_name(co->co_cvec, "termfirstkeys")) == NULL)
|
||||
goto done;
|
||||
|
|
@ -1167,10 +1179,10 @@ yang2cli_post(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
}
|
||||
else if (ykeyword == Y_LEAF || ykeyword == Y_LEAF_LIST){
|
||||
else if (ypkeyword == Y_LEAF || ypkeyword == Y_LEAF_LIST){
|
||||
char *origtype = NULL;
|
||||
yang_stmt *yrestype = NULL;
|
||||
if (yang_type_get(y, &origtype, &yrestype, NULL, NULL, NULL, NULL, NULL) < 0)
|
||||
if (yang_type_get(yp, &origtype, &yrestype, NULL, NULL, NULL, NULL, NULL) < 0)
|
||||
goto done;
|
||||
if (origtype && strcmp(origtype,"empty") != 0)
|
||||
if ((co->co_cvec = cvec_add_name(co->co_cvec, "termleaf")) == NULL)
|
||||
|
|
@ -1179,16 +1191,14 @@ yang2cli_post(clicon_handle h,
|
|||
free(origtype);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ((yc = yang_find_datanode(y, co->co_command)) == NULL)
|
||||
} /* empty */
|
||||
/* note This is quadratic, ie highly inefficient */
|
||||
if ((yc = yang_find_datanode(yp, co->co_command)) == NULL)
|
||||
continue;
|
||||
yciskey = yang_keyword_get(y) == Y_LIST && yang_key_match(y, co->co_command, NULL);
|
||||
/* If leaf add "leafvar" label for non-key leafs
|
||||
* Not a key leaf?
|
||||
* : y is LIST &
|
||||
*/
|
||||
if ((yang_keyword_get(yc) == Y_LEAF) ||
|
||||
yang_keyword_get(yc) == Y_LEAF_LIST){
|
||||
yciskey = ypkeyword == Y_LIST && yang_key_match(yp, co->co_command, NULL);
|
||||
switch (yang_keyword_get(yc)){
|
||||
case Y_LEAF:
|
||||
case Y_LEAF_LIST:
|
||||
/* add empty show
|
||||
regular should have ; on last
|
||||
other ; should be marked as ;
|
||||
|
|
@ -1202,9 +1212,6 @@ yang2cli_post(clicon_handle h,
|
|||
coe = co_insert(co_pt_get(co), coe);
|
||||
}
|
||||
/* XXX move to next recursion level ? */
|
||||
int j;
|
||||
cg_obj *coj;
|
||||
|
||||
if (!yciskey)
|
||||
for (j = 0; j<pt_len_get(co_pt_get(co)); j++){
|
||||
if ((coj = pt_vec_i_get(co_pt_get(co), j)) == NULL)
|
||||
|
|
@ -1214,6 +1221,9 @@ yang2cli_post(clicon_handle h,
|
|||
if ((coj->co_cvec = cvec_add_name(coj->co_cvec, "leafvar")) == NULL)
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* If state: Add nonconfig label*/
|
||||
if (!yang_config(yc)){
|
||||
|
|
@ -1222,78 +1232,97 @@ yang2cli_post(clicon_handle h,
|
|||
}
|
||||
/* If y is list and yc is key, then call with y */
|
||||
if (yciskey){
|
||||
if (yang2cli_post(h, co, co_pt_get(co), 0, y, yc) < 0) // note y not yc
|
||||
if (yang2cli_post(h, co, co_pt_get(co), 0, yp, yc) < 0) // note y not yc
|
||||
goto done;
|
||||
}
|
||||
else if (yang2cli_post(h, co, co_pt_get(co), 0, yc, NULL) < 0)
|
||||
goto done;
|
||||
}
|
||||
} /* for */
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Autocli generator
|
||||
* Note mix of compile-time runtime
|
||||
/*! Generate clispec for all modules in yspec (except excluded)
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] yspec Top-level Yang statement of type Y_SPEC
|
||||
* @param[in] treename Name of tree
|
||||
* @param[in] xautocli Autocli config tree (instance of clixon-autocli.yang)
|
||||
* @param[in] printgen Log the generated CLIgen syntax
|
||||
* @note Tie-break of same top-level symbol: prefix is NYI
|
||||
*/
|
||||
int
|
||||
yang2cli_yspec(clicon_handle h,
|
||||
yang_stmt *yn,
|
||||
char *name0,
|
||||
yang_stmt *yspec,
|
||||
char *treename,
|
||||
int printgen)
|
||||
{
|
||||
int retval = -1;
|
||||
parse_tree *pt0 = NULL;
|
||||
cbuf *cb0 = NULL;
|
||||
genmodel_type gt;
|
||||
char *excludelist;
|
||||
char **exvec = NULL;
|
||||
int nexvec = 0;
|
||||
int e;
|
||||
yang_stmt *ym;
|
||||
pt_head *ph;
|
||||
size_t len0;
|
||||
|
||||
int retval = -1;
|
||||
parse_tree *pt0 = NULL;
|
||||
yang_stmt *ymod;
|
||||
pt_head *ph;
|
||||
int enable;
|
||||
cbuf *cb = NULL;
|
||||
char *prefix;
|
||||
cg_obj *co;
|
||||
int previ=0;
|
||||
int i;
|
||||
|
||||
if ((pt0 = pt_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "pt_new");
|
||||
goto done;
|
||||
}
|
||||
/* List of modules that should not generate autocli */
|
||||
if ((excludelist = clicon_option_str(h, "CLICON_CLI_AUTOCLI_EXCLUDE")) != NULL){
|
||||
if ((exvec = clicon_strsep(excludelist, " \t", &nexvec)) == NULL)
|
||||
goto done;
|
||||
}
|
||||
gt = clicon_cli_genmodel_type(h);
|
||||
if ((cb0 = cbuf_new()) == NULL){
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_XML, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
/* Traverse YANG, loop through all modules and generate CLI */
|
||||
ym = NULL;
|
||||
while ((ym = yn_each(yn, ym)) != NULL){
|
||||
/* Check if module is in exclude list */
|
||||
for (e = 0; e < nexvec; e++){
|
||||
if (strcmp(yang_argument_get(ym), exvec[e]) == 0)
|
||||
break;
|
||||
}
|
||||
if (e < nexvec)
|
||||
continue;
|
||||
len0 = cbuf_len(cb0);
|
||||
if (yang2cli_stmt(h, ym, gt, 0, cb0) < 0)
|
||||
ymod = NULL;
|
||||
while ((ymod = yn_each(yspec, ymod)) != NULL){
|
||||
/* Filter module name according to cli_autocli.yang setting
|
||||
* Default is pass and ordering is significant
|
||||
*/
|
||||
if (autocli_module(h, yang_argument_get(ymod), &enable) < 0)
|
||||
goto done;
|
||||
if (len0 != cbuf_len(cb0))
|
||||
clicon_debug(1, "%s Generated auto-cli for %s", __FUNCTION__, yang_argument_get(ym));
|
||||
}
|
||||
if (printgen)
|
||||
clicon_log(LOG_NOTICE, "%s: Top-level cli-spec %s:\n%s",
|
||||
__FUNCTION__, name0, cbuf_get(cb0));
|
||||
else
|
||||
clicon_debug(2, "%s: Top-level cli-spec %s:\n%s",
|
||||
__FUNCTION__, name0, cbuf_get(cb0));
|
||||
|
||||
/* load top-level yangspec cli syntax (that point to modules) */
|
||||
if (cligen_parse_str(cli_cligen(h), cbuf_get(cb0), "yang2cli", pt0, NULL) < 0)
|
||||
goto done;
|
||||
if (!enable)
|
||||
continue;
|
||||
cbuf_reset(cb);
|
||||
if (yang2cli_stmt(h, ymod, 0, cb) < 0)
|
||||
goto done;
|
||||
if (cbuf_len(cb) == 0)
|
||||
continue;
|
||||
/* Note Tie-break of same top-level symbol: prefix is NYI
|
||||
* Needs to move cligen_parse_str() call here instead of later
|
||||
*/
|
||||
if ((prefix = yang_find_myprefix(ymod)) == NULL){
|
||||
clicon_err(OE_YANG, 0, "Module %s lacks prefix", yang_argument_get(ymod)); /* shouldnt happen */
|
||||
goto done;
|
||||
}
|
||||
/* Parse the buffer using cligen parser. load cli syntax */
|
||||
if (cligen_parse_str(cli_cligen(h), cbuf_get(cb), "yang2cli", pt0, NULL) < 0)
|
||||
goto done;
|
||||
/* Add prefix: assume new are appended */
|
||||
for (i=previ; i<pt_len_get(pt0); i++){
|
||||
if ((co = pt_vec_i_get(pt0, i)) != NULL)
|
||||
co_prefix_set(co, prefix);
|
||||
}
|
||||
/* Post-processing, iterate over the generated cligen parse-tree with corresponding yang
|
||||
* Note cannot do it inline in yang2cli above since:
|
||||
* 1. labels cannot be set on "empty"
|
||||
* 2. a; <a>, fn() cannot be set properly
|
||||
*/
|
||||
if (yang2cli_post(h, NULL, pt0, previ, ymod, NULL) < 0)
|
||||
goto done;
|
||||
previ = pt_len_get(pt0);
|
||||
clicon_debug(1, "%s Generated auto-cli for %s", __FUNCTION__, yang_argument_get(ymod));
|
||||
if (printgen)
|
||||
clicon_log(LOG_NOTICE, "%s: Top-level cli-spec %s:\n%s",
|
||||
__FUNCTION__, treename, cbuf_get(cb));
|
||||
else
|
||||
clicon_debug(2, "%s: Top-level cli-spec %s:\n%s",
|
||||
__FUNCTION__, treename, cbuf_get(cb));
|
||||
} /* ymod */
|
||||
/* Resolve the expand callback functions in the generated syntax.
|
||||
* This "should" only be GENERATE_EXPAND_XMLDB
|
||||
* handle=NULL for global namespace, this means expand callbacks must be in
|
||||
|
|
@ -1301,44 +1330,21 @@ yang2cli_yspec(clicon_handle h,
|
|||
*/
|
||||
if (cligen_expandv_str2fn(pt0, (expandv_str2fn_t*)clixon_str2fn, NULL) < 0)
|
||||
goto done;
|
||||
/* Post-processing, iterate over the generated cligen parse-tree with corresponding yang
|
||||
* Note cannot do it inline in yang2cli above since:
|
||||
* 1. labels cannot be set on "empty"
|
||||
* 2. a; <a>, fn() cannot be set properly
|
||||
*/
|
||||
ym = NULL;
|
||||
while ((ym = yn_each(yn, ym)) != NULL){
|
||||
/* Check if module is in exclude list */
|
||||
for (e = 0; e < nexvec; e++){
|
||||
if (strcmp(yang_argument_get(ym), exvec[e]) == 0)
|
||||
break;
|
||||
}
|
||||
if (e < nexvec)
|
||||
continue;
|
||||
/* Top level find co from yang:
|
||||
* XXX: top-level without namespace means check parsetree symbol against each module
|
||||
* This maye break if there are two top-level symbols with the same name
|
||||
*/
|
||||
if (yang2cli_post(h, NULL, pt0, 0, ym, NULL) < 0)
|
||||
goto done;
|
||||
}
|
||||
/* Append cligen tree and name it */
|
||||
if ((ph = cligen_ph_add(cli_cligen(h), name0)) == NULL)
|
||||
if ((ph = cligen_ph_add(cli_cligen(h), treename)) == NULL)
|
||||
goto done;
|
||||
if (cligen_ph_parsetree_set(ph, pt0) < 0)
|
||||
goto done;
|
||||
#if 0
|
||||
if (printgen){
|
||||
clicon_log(LOG_NOTICE, "%s: Top-level cli-spec %s", __FUNCTION__, name0);
|
||||
clicon_log(LOG_NOTICE, "%s: Top-level cli-spec %s", __FUNCTION__, treename);
|
||||
pt_print1(stderr, pt0, 0);
|
||||
}
|
||||
#endif
|
||||
retval = 0;
|
||||
done:
|
||||
if (exvec)
|
||||
free(exvec);
|
||||
if (cb0)
|
||||
cbuf_free(cb0);
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue