* Support of yangmodels supported, see test_yangmodels.sh

* Added -o "<option>=<value>" command-line option to all programs: backend, cli, netconf, restconf.
* Ignore CR(\r) in yang files for DOS files
This commit is contained in:
Olof hagsand 2019-01-10 20:52:19 +01:00
parent c7e847cd24
commit 207858e20d
26 changed files with 635 additions and 256 deletions

View file

@ -87,9 +87,10 @@ exp ({integer}|{real})[eE][+-]{integer}
%s ESCAPE
%%
<START>[ \t]
<START>\n { _JY->jy_linenum++; }
<START>\r { }
<START>\r
<START><<EOF>> { return J_EOF; }
<START>\{ { return *yytext; }
<START>\} { return *yytext; }

View file

@ -111,7 +111,6 @@ clicon_option_dump(clicon_handle h,
clicon_debug(dbglevel, "%s = NULL", keys[i]);
}
free(keys);
}
/*! Read filename and set values to global options registry. XML variant.
@ -216,6 +215,42 @@ parse_configfile(clicon_handle h,
return retval;
}
/*! Add configuration option overriding file setting
* Add to clicon_options hash, and to clicon_conf_xml tree
* @param[in] h Clicon handle
* @param[in] name Name of configuration option (see clixon-config.yang)
* @param[in] value String value
* @retval 0 OK
* @retval -1 Error
* @see clicon_options_main For loading options from file
*/
int
clicon_option_add(clicon_handle h,
char *name,
char *value)
{
int retval = -1;
clicon_hash_t *copt = clicon_options(h);
cxobj *x;
if (strcmp(name, "CLICON_FEATURE")==0 ||
strcmp(name, "CLICON_YANG_DIR")==0){
if ((x = clicon_conf_xml(h)) == NULL)
goto done;
if (xml_parse_va(&x, NULL, "<%s>%s</%s>",
name, value, name) < 0)
goto done;
}
if (hash_add(copt,
name,
value,
strlen(value)+1) == NULL)
goto done;
retval = 0;
done:
return retval;
}
/*! Parse clixon yang file. Parse XML config file. Initialize option values
*
* Set default options, Read config-file, Check that all values are set.
@ -265,7 +300,7 @@ clicon_options_main(clicon_handle h,
/* Set clixon_conf pointer to handle */
clicon_conf_xml_set(h, xconfig);
/* Parse clixon yang spec */
if (yang_parse(h, NULL, "clixon-config", NULL, yspec) < 0)
if (yang_spec_parse_module(h, "clixon-config", NULL, yspec) < 0)
goto done;
clicon_conf_xml_set(h, NULL);
if (xconfig)

View file

@ -2413,7 +2413,7 @@ yang_enum_int_value(cxobj *node,
goto done;
if ((ytype = yang_find((yang_node *)ys, Y_TYPE, NULL)) == NULL)
goto done;
if (yang_type_resolve(ys, ytype, &yrestype,
if (yang_type_resolve(ys, ys, ytype, &yrestype,
NULL, NULL, NULL, NULL) < 0)
goto done;
if (yrestype==NULL || strcmp(yrestype->ys_argument, "enumeration"))

View file

@ -106,6 +106,7 @@ ncname {namestart}{namechar}*
<START,TEXTDECL>[ \t] ;
<START,STATEA,CMNT,TEXTDECL>\n { _YA->ya_linenum++; }
<START,STATEA,CMNT,TEXTDECL>\r
<START>{ncname} { clixon_xml_parselval.string = strdup(yytext);
return NAME; /* rather be catch-all */

View file

@ -34,6 +34,16 @@
* Yang functions
* @see https://tools.ietf.org/html/rfc6020 YANG 1.0
* @see https://tools.ietf.org/html/rfc7950 YANG 1.1
*
* yang_spec_parse_module
* \
* yang_spec_parse_file-> yang_parse_post->yang_parse_recurse->yang_parse_module
* \ / v
* yang_spec_load_dir ------------------------------------> yang_parse_filename
* v
* yang_parse_file
* v
* yang_parse_str
*/
#ifdef HAVE_CONFIG_H
@ -1068,7 +1078,8 @@ ys_populate_leaf(yang_stmt *ys,
yparent = ys->ys_parent; /* Find parent: list/container */
/* 1. Find type specification and set cv type accordingly */
if (yang_type_get(ys, &type, &yrestype, &options, NULL, NULL, &fraction_digits) < 0)
if (yang_type_get(ys, &type, &yrestype, &options, NULL, NULL, &fraction_digits)
< 0)
goto done;
restype = yrestype?yrestype->ys_argument:NULL;
if (clicon_type2cv(type, restype, &cvtype) < 0) /* This handles non-resolved also */
@ -1213,7 +1224,7 @@ ys_populate_range(yang_stmt *ys,
clicon_err(OE_YANG, 0, "parent should be type");
goto done;
}
if (yang_type_resolve(ys, (yang_stmt*)yparent, &yrestype,
if (yang_type_resolve(ys, ys, (yang_stmt*)yparent, &yrestype,
&options, NULL, NULL, &fraction_digits) < 0)
goto done;
restype = yrestype?yrestype->ys_argument:NULL;
@ -1467,7 +1478,7 @@ ys_populate_feature(clicon_handle h,
cv_name_set(cv, feature);
cv_bool_set(cv, found);
if (found)
clicon_debug(1, "%s %s:%s", __FUNCTION__, module, feature);
clicon_debug(2, "%s %s:%s", __FUNCTION__, module, feature);
ys->ys_cv = cv;
ok:
retval = 0;
@ -2085,7 +2096,7 @@ yang_parse_recurse(clicon_handle h,
subrevision = NULL;
/* if already loaded, ignore, else parse the file */
if (yang_find((yang_node*)ysp,
keyw=Y_IMPORT?Y_MODULE:Y_SUBMODULE,
keyw==Y_IMPORT?Y_MODULE:Y_SUBMODULE,
submodule) == NULL){
/* recursive call */
if ((subymod = yang_parse_module(h, submodule, subrevision, ysp)) == NULL)
@ -2249,7 +2260,9 @@ yang_merge_submodules(clicon_handle h,
}
modname = yb->ys_argument;
if ((ymod = yang_find((yang_node*)yspec, Y_MODULE, modname)) == NULL){
clicon_err(OE_YANG, ENOENT, "Module %s which submodule %s belongs to is not found", modname, ysubm->ys_argument);
clicon_err(OE_YANG, ENOENT, "Submodule %s is loaded before/without its main module %s (you need to load the submodule together with or after the main module)",
ysubm->ys_argument,
modname);
goto done;
}
/* Move sub-module statements to modules
@ -2304,64 +2317,29 @@ yang_merge_submodules(clicon_handle h,
* yang_parse_str # Set up yacc parser and call it given a string
* clixon_yang_parseparse # Actual yang parsing using yacc
*/
int
yang_parse(clicon_handle h,
const char *filename,
const char *module,
const char *revision,
yang_spec *yspec)
static int
yang_parse_post(clicon_handle h,
yang_spec *yspec,
int modnr)
{
int retval = -1;
yang_stmt *ymod = NULL; /* Top-level yang (sub)module */
int i;
int modnr; /* Existing number of modules */
char *base = NULL;;
/* Apply steps 2.. on new modules, ie ones after modnr. */
modnr = yspec->yp_len;
if (filename){
/* Find module, and do not load file if module already exists */
if (basename(filename) == NULL){
clicon_err(OE_YANG, errno, "No basename");
goto done;
}
if ((base = strdup(basename(filename))) == NULL){
clicon_err(OE_YANG, errno, "strdup");
goto done;
}
if (index(base, '@') != NULL)
*index(base, '@') = '\0';
if (yang_find((yang_node*)yspec, Y_MODULE, base) != NULL)
goto ok;
if ((ymod = yang_parse_filename(filename, yspec)) == NULL)
goto done;
}
else {
/* Do not load module if it already exists */
if (yang_find((yang_node*)yspec, Y_MODULE, module) != NULL)
goto ok;
if ((ymod = yang_parse_module(h, module, revision, yspec)) == NULL)
goto done;
}
int retval = -1;
int i;
/* 1: Parse from text to yang parse-tree. */
/* Iterate through modules */
if (yang_parse_recurse(h, ymod, yspec) < 0)
goto done;
for (i=modnr; i<yspec->yp_len; i++)
if (yang_parse_recurse(h, yspec->yp_stmt[i], yspec) < 0)
goto done;
/* 2. Check cardinality maybe this should be done after grouping/augment */
for (i=modnr; i<yspec->yp_len; i++) /* XXX */
for (i=modnr; i<yspec->yp_len; i++)
if (yang_cardinality(h, yspec->yp_stmt[i], yspec->yp_stmt[i]->ys_argument) < 0)
goto done;
/* 3: Merge sub-modules with modules - after this step, no submodules exist
* In the merge, remove submodule headers
*/
for (i=modnr; i<yspec->yp_len; i++){
if (yspec->yp_stmt[i]->ys_keyword != Y_SUBMODULE)
continue;
}
i = 0;
i = modnr;
while (i<yspec->yp_len){
int j;
if (yspec->yp_stmt[i]->ys_keyword != Y_SUBMODULE){
@ -2416,7 +2394,48 @@ yang_parse(clicon_handle h,
for (i=modnr; i<yspec->yp_len; i++)
if (yang_apply((yang_node*)yspec->yp_stmt[i], -1, ys_schemanode_check, NULL) < 0)
goto done;
/* Return main module parsed in step 1 */
retval = 0;
done:
return retval;
}
/*! Parse yang specification and its dependencies recursively given module
* @param[in] h clicon handle
* @param[in] module Module name, or absolute filename (including dir)
* @param[in] dir Directory where to look for modules and sub-modules
* @param[in] revision Revision, or NULL
* @param[in,out] yspec Modules parse are added to this yangspec
* @retval 0 OK
* @retval -1 Error
* @see yang_spec_parse_file
*/
int
yang_spec_parse_module(clicon_handle h,
const char *module,
const char *revision,
yang_spec *yspec)
{
int retval = -1;
int modnr; /* Existing number of modules */
char *base = NULL;;
if (yspec == NULL){
clicon_err(OE_YANG, EINVAL, "yang spec is NULL");
goto done;
}
if (module == NULL){
clicon_err(OE_YANG, EINVAL, "yang module not set");
goto done;
}
/* Apply steps 2.. on new modules, ie ones after modnr. */
modnr = yspec->yp_len;
/* Do not load module if it already exists */
if (yang_find((yang_node*)yspec, Y_MODULE, module) != NULL)
goto ok;
if (yang_parse_module(h, module, revision, yspec) == NULL)
goto done;
if (yang_parse_post(h, yspec, modnr) < 0)
goto done;
ok:
retval = 0;
done:
@ -2425,6 +2444,132 @@ yang_parse(clicon_handle h,
return retval;
}
/*! Parse yang specification and its dependencies recursively given filename
* @param[in] h clicon handle
* @param[in] filename Actual filename (including dir and revision)
* @param[in] dir Directory for sub-modules
* @param[in,out] yspec Modules parse are added to this yangspec
* @retval 0 OK
* @retval -1 Error
* @see yang_spec_parse_module for yang dir,module,revision instead of
* actual filename
* @see yang_spec_load_dir For loading all files in a directory
*/
int
yang_spec_parse_file(clicon_handle h,
const char *filename,
yang_spec *yspec)
{
int retval = -1;
int modnr; /* Existing number of modules */
char *base = NULL;;
/* Apply steps 2.. on new modules, ie ones after modnr. */
modnr = yspec->yp_len;
/* Find module, and do not load file if module already exists */
if (basename(filename) == NULL){
clicon_err(OE_YANG, errno, "No basename");
goto done;
}
if ((base = strdup(basename(filename))) == NULL){
clicon_err(OE_YANG, errno, "strdup");
goto done;
}
if (index(base, '@') != NULL)
*index(base, '@') = '\0';
if (yang_find((yang_node*)yspec, Y_MODULE, base) != NULL)
goto ok;
if (yang_parse_filename(filename, yspec) == NULL)
goto done;
if (yang_parse_post(h, yspec, modnr) < 0)
goto done;
ok:
retval = 0;
done:
if (base)
free(base);
return retval;
}
/*! Load all yang modules in directory
* @param[in] h Clicon handle
* @param[in] dir Load all yang modules in this directory
* @param[in,out] yspec Modules parse are added to this yangspec
* @retval 0 OK
* @retval -1 Error
* @see yang_spec_parse_file
*/
int
yang_spec_load_dir(clicon_handle h,
char *dir,
yang_spec *yspec)
{
int retval = -1;
int ndp;
struct dirent *dp = NULL;
int i;
char filename[MAXPATHLEN];
char *base = NULL; /* filename without dir */
char *b;
int j;
int modnr;
/* Get plugin objects names from plugin directory */
if((ndp = clicon_file_dirent(dir, &dp, "(.yang)$", S_IFREG)) < 0)
goto done;
if (ndp == 0)
clicon_log(LOG_WARNING, "%s: No yang files found in %s",
__FUNCTION__, dir);
/* Apply post steps on new modules, ie ones after modnr. */
modnr = yspec->yp_len;
/* Load all yang files in dir */
for (i = 0; i < ndp; i++) {
/* base = module name [+ @rev ] + .yang */
if (base)
free(base);
if ((base = strdup(dp[i].d_name)) == NULL){
clicon_err(OE_UNIX, errno, "strdup");
goto done;
}
*rindex(base, '.') = '\0'; /* strip postfix .yang */
/* base = module name [+ @rev]
* if it hasnt @rev then prefer it (dont check other files w @rev)
* Otherwise see if there is a newer
*/
if ((b = index(base, '@')) != NULL){
*b = '\0';
/* base = module name */
/* Entries are sorted, see if later entry exists (include @), if so
* skip this one and take last.
* Assume file without @ is last
*/
for (j = (i+1); j < ndp; j++)
if (strncmp(base, dp[j].d_name, strlen(base)) == 0)
break;
if (j<ndp){ /* exists later entry */
clicon_debug(1, "%s skip %s", __FUNCTION__, dp[i].d_name);
continue;
}
}
snprintf(filename, MAXPATHLEN-1, "%s/%s", dir, dp[i].d_name);
/* Dont parse if already exists */
if (yang_find((yang_node*)yspec, Y_MODULE, base) != NULL ||
yang_find((yang_node*)yspec, Y_SUBMODULE, base) != NULL)
continue;
if (yang_parse_filename(filename, yspec) == NULL)
goto done;
}
if (yang_parse_post(h, yspec, modnr) < 0)
goto done;
retval = 0;
done:
if (base)
free(base);
return retval;
}
/*! Apply a function call recursively on all yang-stmt s recursively
*
* Recursively traverse all yang-nodes in a parse-tree and apply fn(arg) for
@ -2835,121 +2980,6 @@ yang_config(yang_stmt *ys)
return 1;
}
/*! Parse yang specification and its dependencies recursively given module
* @param[in] h clicon handle
* @param[in] module Module name, or absolute filename (including dir)
* @param[in] dir Directory where to look for modules and sub-modules
* @param[in] revision Revision, or NULL
* @param[in,out] yspec Modules parse are added to this yangspec
* @retval 0 OK
* @retval -1 Error
* @see yang_spec_parse_file
*/
int
yang_spec_parse_module(clicon_handle h,
char *module,
char *revision,
yang_spec *yspec)
{
int retval = -1;
if (yspec == NULL){
clicon_err(OE_YANG, EINVAL, "yang spec is NULL");
goto done;
}
if (module == NULL){
clicon_err(OE_YANG, EINVAL, "yang module not set");
goto done;
}
/* Sanity check - use yang_spec_parse_file instead */
if (strlen(module) && module[0] == '/'){
clicon_err(OE_YANG, EINVAL, "yang module illegal format");
goto done;
}
if (yang_parse(h, NULL, module, revision, yspec) < 0)
goto done;
retval = 0;
done:
return retval;
}
/*! Parse yang specification and its dependencies recursively given filename
* @param[in] h clicon handle
* @param[in] filename Actual filename (including dir and revision)
* @param[in] dir Directory for sub-modules
* @param[in,out] yspec Modules parse are added to this yangspec
* @retval 0 OK
* @retval -1 Error
* @see yang_spec_parse_module for yang dir,module,revision instead of actual filename
*/
int
yang_spec_parse_file(clicon_handle h,
char *filename,
yang_spec *yspec)
{
int retval = -1;
if (yspec == NULL){
clicon_err(OE_YANG, EINVAL, "yang spec is NULL");
goto done;
}
if (yang_parse(h, filename, NULL, NULL, yspec) < 0)
goto done;
retval = 0;
done:
return retval;
}
/*! Load all yang modules in directory
* @param[in] h Clicon handle
* @param[in] dir Load all yang modules in this directory
* @param[in,out] yspec Modules parse are added to this yangspec
* @retval 0 OK
* @retval -1 Error
*/
int
yang_spec_load_dir(clicon_handle h,
char *dir,
yang_spec *yspec)
{
int retval = -1;
int ndp;
struct dirent *dp = NULL;
int i;
char filename[MAXPATHLEN];
char *base;
char *b;
int j;
int len;
/* Get plugin objects names from plugin directory */
if((ndp = clicon_file_dirent(dir, &dp, "(.yang)$", S_IFREG)) < 0)
goto done;
/* Load all yang files */
for (i = 0; i < ndp; i++) {
base = dp[i].d_name;
/* Entries are sorted, see if later entry exists (include @), if so skip
* this one and take last.
*/
if ((b = index(base, '@')) != NULL)
len = b-base;
else
len = strlen(base);
/* remove duplicates: there may be cornercases that dont work, eg
* mix of revisions and not? */
for (j = (i+1); j < ndp; j++)
if (strncmp(base, dp[j].d_name, len) == 0)
break;
if (j<ndp) /* exists later entry */
continue;
snprintf(filename, MAXPATHLEN-1, "%s/%s", dir, dp[i].d_name);
if (yang_parse(h, filename, NULL, NULL, yspec) < 0)
goto done;
}
retval = 0;
done:
return retval;
}
/*! Given a yang node, translate the argument string to a cv vector
*

View file

@ -513,8 +513,12 @@ yang_cardinality(clicon_handle h,
continue;
/* Find entry in yang cardinality table from parent/child keyword pair */
if ((yc = ycard_find(pk, ck, ycplist, 1)) == NULL){
clicon_err(OE_YANG, 0, "%s: \"%s\" is child of \"%s\", but should not be",
modname, yang_key2str(ck), yang_key2str(pk));
clicon_err(OE_YANG, 0, "%s: \"%s\"(%s) is child of \"%s\"(%s), but should not be",
modname,
yang_key2str(ck),
ys->ys_argument,
yang_key2str(pk),
yt->ys_argument);
goto done;
}
}

View file

@ -103,9 +103,10 @@ identifier [A-Za-z_][A-Za-z0-9_\-\.]*
%%
/* Common tokens */
<KEYWORD,BOOLEAN,INTEGER,STRARG,ARGUMENT,STRING>[ \t]
<KEYWORD,STRING,UNKNOWN><<EOF>> { return MY_EOF; }
<KEYWORD,BOOLEAN,INTEGER,STRARG,STRING,ARGUMENT,UNKNOWN>[ \t]
<KEYWORD,STRING,UNKNOWN,COMMENT2><<EOF>> { return MY_EOF; }
<KEYWORD,BOOLEAN,INTEGER,STRARG,STRING,COMMENT1,UNKNOWN>\n { _YY->yy_linenum++; }
<KEYWORD,BOOLEAN,INTEGER,STRARG,STRING,COMMENT1,UNKNOWN>\r
<KEYWORD,STRING>"/*" { _YY->yy_lex_state = YYSTATE; BEGIN(COMMENT1); }
<KEYWORD,STRING>"//" { _YY->yy_lex_state = YYSTATE; BEGIN(COMMENT2); }
@ -194,7 +195,8 @@ identifier [A-Za-z_][A-Za-z0-9_\-\.]*
<UNKNOWN>: { return *yytext; }
<UNKNOWN>; { BEGIN(KEYWORD); return *yytext; }
<UNKNOWN>[ \t] { return ' '; }
<UNKNOWN>\" { _YY->yy_lex_string_state =UNKNOWN; BEGIN(STRINGDQ); return *yytext; }
<UNKNOWN>\{ { BEGIN(KEYWORD); return *yytext; }
<UNKNOWN>. { clixon_yang_parselval.string = strdup(yytext);
return CHAR; }
@ -220,14 +222,14 @@ identifier [A-Za-z_][A-Za-z0-9_\-\.]*
<STRING>\{ { BEGIN(KEYWORD); return *yytext; }
<STRING>; { BEGIN(KEYWORD); return *yytext; }
<STRING>\" { _YY->yy_lex_string_state =STRING; BEGIN(STRINGDQ); return DQ; }
<STRING>\" { _YY->yy_lex_string_state =STRING; BEGIN(STRINGDQ); return *yytext; }
<STRING>\' { _YY->yy_lex_string_state =STRING; BEGIN(STRINGSQ); return SQ; }
<STRING>\+ { return *yytext; }
<STRING>. { clixon_yang_parselval.string = strdup(yytext);
return CHAR;}
<STRINGDQ>\\ { _YY->yy_lex_state = STRINGDQ; BEGIN(ESCAPE); }
<STRINGDQ>\" { BEGIN(_YY->yy_lex_string_state); return DQ; }
<STRINGDQ>\" { BEGIN(_YY->yy_lex_string_state); return *yytext; }
<STRINGDQ>\n { _YY->yy_linenum++; clixon_yang_parselval.string = strdup(yytext); return CHAR;}
<STRINGDQ>. { clixon_yang_parselval.string = strdup(yytext);
return CHAR;}

View file

@ -56,7 +56,6 @@
}
%token MY_EOF
%token DQ /* Double quote: " */
%token SQ /* Single quote: ' */
%token <string> CHAR
%token <string> IDENTIFIER
@ -70,7 +69,8 @@
%type <string> integer_value_str
%type <string> identifier_ref
%type <string> abs_schema_nodeid
%type <string> desc_schema_node_str
%type <string> desc_schema_nodeid_strs
%type <string> desc_schema_nodeid_str
%type <string> desc_schema_nodeid
%type <string> node_identifier
%type <string> identifier_str
@ -365,19 +365,6 @@ file : module_stmt MY_EOF
{ clicon_debug(2,"file->submodule-stmt"); YYACCEPT; }
;
/* For extensions */
unknown_stmt : ustring ':' ustring ';'
{ char *id; if ((id=string_del_join($1, ":", $3)) == NULL) _YYERROR("unknown_stmt");
if (ysp_add(_yy, Y_UNKNOWN, id, NULL) == NULL) _YYERROR("unknown_stmt");
clicon_debug(2,"unknown-stmt -> ustring : ustring");
}
| ustring ':' ustring ' ' string ';'
{ char *id; if ((id=string_del_join($1, ":", $3)) == NULL) _YYERROR("unknwon_stmt");
if (ysp_add(_yy, Y_UNKNOWN, id, $5) == NULL){ _YYERROR("unknwon_stmt"); }
clicon_debug(2,"unknown-stmt -> ustring : ustring string");
}
;
/* module identifier-arg-str */
module_stmt : K_MODULE identifier_str
{ if ((_YY->yy_module = ysp_add_push(_yy, Y_MODULE, $2)) == NULL) _YYERROR("module_stmt");
@ -591,15 +578,14 @@ revision_date_stmt : K_REVISION_DATE string stmtend /* XXX date-arg-str */
extension_stmt : K_EXTENSION identifier_str ';'
{ if (ysp_add(_yy, Y_EXTENSION, $2, NULL) == NULL) _YYERROR("extension_stmt");
clicon_debug(2,"extenstion-stmt -> EXTENSION id-arg-str ;"); }
clicon_debug(2,"extenstion-stmt -> EXTENSION id-str ;"); }
| K_EXTENSION identifier_str
{ if (ysp_add_push(_yy, Y_EXTENSION, $2) == NULL) _YYERROR("extension_stmt"); }
'{' extension_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("extension_stmt");
clicon_debug(2,"extension-stmt -> FEATURE id-arg-str { extension-substmts }"); }
clicon_debug(2,"extension-stmt -> EXTENSION id-str { extension-substmts }"); }
;
/* extension substmts */
extension_substmts : extension_substmts extension_substmt
{ clicon_debug(2,"extension-substmts -> extension-substmts extension-substmt"); }
@ -615,10 +601,28 @@ extension_substmt : argument_stmt { clicon_debug(2,"extension-substmt -> argu
| { clicon_debug(2,"extension-substmt -> "); }
;
argument_stmt : K_ARGUMENT identifier_str ';' { free($2); }
| K_ARGUMENT identifier_str '{' yin_element_stmt1 '}' { free($2); }
argument_stmt : K_ARGUMENT identifier_str ';'
{ if (ysp_add(_yy, Y_ARGUMENT, $2, NULL) == NULL) _YYERROR("argument_stmt");
clicon_debug(2,"argument-stmt -> ARGUMENT identifier ;"); }
| K_ARGUMENT identifier_str
{ if (ysp_add_push(_yy, Y_ARGUMENT, $2) == NULL) _YYERROR("argument_stmt"); }
'{' argument_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("argument_stmt");
clicon_debug(2,"argument-stmt -> ARGUMENT { argument-substmts }"); }
;
/* argument substmts */
argument_substmts : argument_substmts argument_substmt
{ clicon_debug(2,"argument-substmts -> argument-substmts argument-substmt"); }
| argument_substmt
{ clicon_debug(2,"argument-substmts -> argument-substmt"); }
;
argument_substmt : yin_element_stmt1 { clicon_debug(2,"argument-substmt -> yin-element-stmt1");}
| unknown_stmt { clicon_debug(2,"argument-substmt -> unknown-stmt");}
;
/* Example of optional rule, eg [yin-element-stmt] */
yin_element_stmt1 : K_YIN_ELEMENT bool_str stmtend {free($2);}
;
@ -752,6 +756,8 @@ type_body_stmt/* numerical-restrictions */
| bit_stmt { clicon_debug(2,"type-body-stmt -> bit-stmt"); }
/* union-specification */
| type_stmt { clicon_debug(2,"type-body-stmt -> type-stmt"); }
/* Cisco uses this (eg Cisco-IOS-XR-sysadmin-nto-misc-set-hostname.yang) but I dont see this is in the RFC */
| unknown_stmt { clicon_debug(2,"type-body-stmt -> unknown-stmt");}
;
/* range-stmt */
@ -1305,10 +1311,10 @@ uses_substmt : when_stmt { clicon_debug(2,"uses-substmt -> when-stmt
;
/* refine-stmt = refine-keyword sep refine-arg-str */
refine_stmt : K_REFINE desc_schema_node_str ';'
refine_stmt : K_REFINE desc_schema_nodeid_strs ';'
{ if (ysp_add(_yy, Y_REFINE, $2, NULL) == NULL) _YYERROR("refine_stmt");
clicon_debug(2,"refine-stmt -> REFINE id-arg-str ;"); }
| K_REFINE desc_schema_node_str
| K_REFINE desc_schema_nodeid_strs
{ if (ysp_add_push(_yy, Y_REFINE, $2) == NULL) _YYERROR("refine_stmt"); }
'{' refine_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("refine_stmt");
@ -1335,8 +1341,10 @@ refine_substmt : if_feature_stmt { clicon_debug(2,"refine-substmt -> if-fea
| { clicon_debug(2,"refine-substmt -> "); }
;
/* uses-augment-stmt = augment-keyword augment-arg-str */
uses_augment_stmt : K_AUGMENT desc_schema_node_str
/* uses-augment-stmt = augment-keyword augment-arg-str
uses_augment_stmt : K_AUGMENT desc_schema_nodeid_strs
*/
uses_augment_stmt : K_AUGMENT string
{ if (ysp_add_push(_yy, Y_AUGMENT, $2) == NULL) _YYERROR("uses_augment_stmt"); }
'{' augment_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("uses_augment_stmt");
@ -1345,6 +1353,7 @@ uses_augment_stmt : K_AUGMENT desc_schema_node_str
/* augment-stmt = augment-keyword sep augment-arg-str
* XXX abs-schema-nodeid-str is too difficult, it needs the + semantics
augment_stmt : K_AUGMENT abs_schema_nodeid_strs
*/
augment_stmt : K_AUGMENT string
{ if (ysp_add_push(_yy, Y_AUGMENT, $2) == NULL) _YYERROR("augment_stmt"); }
@ -1418,6 +1427,7 @@ rpc_substmt : if_feature_stmt { clicon_debug(2,"rpc-substmt -> if-feature-stm
| grouping_stmt { clicon_debug(2,"rpc-substmt -> grouping-stmt"); }
| input_stmt { clicon_debug(2,"rpc-substmt -> input-stmt"); }
| output_stmt { clicon_debug(2,"rpc-substmt -> output-stmt"); }
| unknown_stmt { clicon_debug(2,"rpc-substmt -> unknown-stmt");}
| { clicon_debug(2,"rpc-substmt -> "); }
;
@ -1481,13 +1491,147 @@ deviation_substmts : deviation_substmts deviation_substmt
deviation_substmt : description_stmt { clicon_debug(2,"deviation-substmt -> description-stmt"); }
| reference_stmt { clicon_debug(2,"deviation-substmt -> reference-stmt"); }
| deviate_not_supported_stmt { clicon_debug(2,"deviation-substmt -> deviate-not-supported-stmt"); }
| deviate_stmt { clicon_debug(2,"deviation-substmt -> deviate-stmt"); }
;
deviate_not_supported_stmt : K_DEVIATE string stmtend
/* RFC7950 differentiates between deviate-not-supported, deviate-add,
* deviate-replave, and deviate-delete. Here all are bundled into a single
* deviate rule. For now, until "deviate" gets supported.
*/
deviate_stmt : K_DEVIATE string ';'
{ if (ysp_add(_yy, Y_DEVIATE, $2, NULL) == NULL) _YYERROR("notification_stmt");
clicon_debug(2,"deviate-not-supported-stmt -> DEVIATE string ;"); }
;
| K_DEVIATE string
{ if (ysp_add_push(_yy, Y_DEVIATE, $2) == NULL) _YYERROR("deviate_stmt"); }
'{' deviate_substmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("deviate_stmt");
clicon_debug(2,"deviate-stmt -> DEVIATE string { deviate-substmts }"); }
;
/* RFC7950 differentiates between deviate-not-supported, deviate-add,
* deviate-replave, and deviate-delete. Here all are bundled into a single
* deviate-substmt rule. For now, until "deviate" gets supported.
*/
deviate_substmts : deviate_substmts deviate_substmt
{ clicon_debug(2,"deviate-substmts -> deviate-substmts deviate-substmt"); }
| deviate_substmt
{ clicon_debug(2,"deviate-substmts -> deviate-substmt"); }
;
/* Bundled */
deviate_substmt : type_stmt { clicon_debug(2,"deviate-substmt -> type-stmt"); }
| units_stmt { clicon_debug(2,"deviate-substmt -> units-stmt"); }
| must_stmt { clicon_debug(2,"deviate-substmt -> must-stmt"); }
| unique_stmt { clicon_debug(2,"deviate-substmt -> unique-stmt"); }
| default_stmt { clicon_debug(2,"deviate-substmt -> default-stmt"); }
| config_stmt { clicon_debug(2,"deviate-substmt -> config-stmt"); }
| mandatory_stmt { clicon_debug(2,"deviate-substmt -> mandatory-stmt"); }
| min_elements_stmt { clicon_debug(2,"deviate-substmt -> min-elements-stmt"); }
| max_elements_stmt { clicon_debug(2,"deviate-substmt -> max-elements-stmt"); }
| { clicon_debug(2,"deviate-substmt -> "); }
;
/* For extensions */
unknown_stmt : ustring ':' ustring ';'
{ char *id; if ((id=string_del_join($1, ":", $3)) == NULL) _YYERROR("unknown_stmt");
if (ysp_add(_yy, Y_UNKNOWN, id, NULL) == NULL) _YYERROR("unknown_stmt");
clicon_debug(2,"unknown-stmt -> ustring : ustring");
}
| ustring ':' ustring string ';'
{ char *id; if ((id=string_del_join($1, ":", $3)) == NULL) _YYERROR("unknown_stmt");
if (ysp_add(_yy, Y_UNKNOWN, id, $4) == NULL){ _YYERROR("unknwon_stmt"); }
clicon_debug(2,"unknown-stmt -> ustring : ustring string");
}
| ustring ':' ustring
{ if (ysp_add_push(_yy, Y_UNKNOWN, NULL) == NULL) _YYERROR("unknown_stmt"); }
'{' yang_stmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("unknown_stmt");
clicon_debug(2,"unknown-stmt -> ustring : ustring { yang-stmts }"); }
| ustring ':' ustring string
{ if (ysp_add_push(_yy, Y_UNKNOWN, NULL) == NULL) _YYERROR("unknown_stmt"); }
'{' yang_stmts '}'
{ if (ystack_pop(_yy) < 0) _YYERROR("unknown_stmt");
clicon_debug(2,"unknown-stmt -> ustring : ustring string { yang-stmts }"); }
;
yang_stmts : yang_stmts yang_stmt { clicon_debug(2,"yang-stmts -> yang-stmts yang-stmt"); }
| yang_stmt { clicon_debug(2,"yang-stmts -> yang-stmt");}
;
yang_stmt : action_stmt { clicon_debug(2,"yang-stmt -> action-stmt");}
| anydata_stmt { clicon_debug(2,"yang-stmt -> anydata-stmt");}
| anyxml_stmt { clicon_debug(2,"yang-stmt -> anyxml-stmt");}
| argument_stmt { clicon_debug(2,"yang-stmt -> argument-stmt");}
| augment_stmt { clicon_debug(2,"yang-stmt -> augment-stmt");}
| base_stmt { clicon_debug(2,"yang-stmt -> base-stmt");}
| bit_stmt { clicon_debug(2,"yang-stmt -> bit-stmt");}
| case_stmt { clicon_debug(2,"yang-stmt -> case-stmt");}
| choice_stmt { clicon_debug(2,"yang-stmt -> choice-stmt");}
| config_stmt { clicon_debug(2,"yang-stmt -> config-stmt");}
| contact_stmt { clicon_debug(2,"yang-stmt -> contact-stmt");}
| container_stmt { clicon_debug(2,"yang-stmt -> container-stmt");}
| default_stmt { clicon_debug(2,"yang-stmt -> default-stmt");}
| description_stmt { clicon_debug(2,"yang-stmt -> description-stmt");}
| deviate_stmt { clicon_debug(2,"yang-stmt -> deviate-stmt");}
/* deviate is not yet implemented, the above may be replaced by the following lines
| deviate_add_stmt { clicon_debug(2,"yang-stmt -> deviate-add-stmt");}
| deviate_delete_stmt { clicon_debug(2,"yang-stmt -> deviate-add-stmt");}
| deviate_replace_stmt { clicon_debug(2,"yang-stmt -> deviate-add-stmt");}
*/
| deviation_stmt { clicon_debug(2,"yang-stmt -> deviation-stmt");}
| enum_stmt { clicon_debug(2,"yang-stmt -> enum-stmt");}
| error_app_tag_stmt { clicon_debug(2,"yang-stmt -> error-app-tag-stmt");}
| error_message_stmt { clicon_debug(2,"yang-stmt -> error-message-stmt");}
| extension_stmt { clicon_debug(2,"yang-stmt -> extension-stmt");}
| feature_stmt { clicon_debug(2,"yang-stmt -> feature-stmt");}
| fraction_digits_stmt { clicon_debug(2,"yang-stmt -> fraction-digits-stmt");}
| grouping_stmt { clicon_debug(2,"yang-stmt -> grouping-stmt");}
| identity_stmt { clicon_debug(2,"yang-stmt -> identity-stmt");}
| if_feature_stmt { clicon_debug(2,"yang-stmt -> if-feature-stmt");}
| import_stmt { clicon_debug(2,"yang-stmt -> import-stmt");}
| include_stmt { clicon_debug(2,"yang-stmt -> include-stmt");}
| input_stmt { clicon_debug(2,"yang-stmt -> input-stmt");}
| key_stmt { clicon_debug(2,"yang-stmt -> key-stmt");}
| leaf_list_stmt { clicon_debug(2,"yang-stmt -> leaf-list-stmt");}
| leaf_stmt { clicon_debug(2,"yang-stmt -> leaf-stmt");}
| length_stmt { clicon_debug(2,"yang-stmt -> length-stmt");}
| list_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| mandatory_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| max_elements_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| min_elements_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| modifier_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| module_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| must_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| namespace_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| notification_stmt { clicon_debug(2,"yang-stmt -> notification-stmt");}
| ordered_by_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| organization_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| output_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| path_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| pattern_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| position_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| prefix_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| presence_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| range_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| reference_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| refine_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| require_instance_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| revision_date_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| revision_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| rpc_stmt { clicon_debug(2,"yang-stmt -> rpc-stmt");}
| status_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| submodule_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| typedef_stmt { clicon_debug(2,"yang-stmt -> typedef-stmt");}
| type_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| unique_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| units_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| uses_augment_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| uses_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| value_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| when_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
| yang_version_stmt { clicon_debug(2,"yang-stmt -> list-stmt");}
/* | yin_element_stmt { clicon_debug(2,"yang-stmt -> list-stmt");} */
;
/* body */
body_stmts : body_stmts body_stmt { clicon_debug(2,"body-stmts -> body-stmts body-stmt"); }
@ -1571,8 +1715,8 @@ qstrings : qstrings '+' qstring
{ $$=$1; clicon_debug(2,"qstrings-> qstring"); }
;
qstring : DQ ustring DQ { $$=$2; clicon_debug(2,"string-> \" ustring \"");}
| DQ DQ { $$=strdup(""); clicon_debug(2,"string-> \" \"");}
qstring : '"' ustring '"' { $$=$2; clicon_debug(2,"string-> \" ustring \"");}
| '"' '"' { $$=strdup(""); clicon_debug(2,"string-> \" \"");}
| SQ ustring SQ { $$=$2; clicon_debug(2,"string-> ' ustring '"); }
;
@ -1596,12 +1740,25 @@ abs_schema_nodeid : abs_schema_nodeid '/' node_identifier
clicon_debug(2,"absolute-schema-nodeid -> / node-identifier"); }
;
desc_schema_node_str : desc_schema_nodeid
{ $$=$1; clicon_debug(2,"descendant-schema-node-str -> descendant-node"); }
desc_schema_nodeid_strs : desc_schema_nodeid_strs '+' desc_schema_nodeid_str
{
int len = strlen($1);
$$ = realloc($1, len + strlen($3) + 1);
sprintf($$+len, "%s", $3);
free($3);
clicon_debug(2,"desc-schema-nodeid-strs-> desc-schema-nodeid-strs + desc-schema-nodeid-str");
}
| desc_schema_nodeid_str
{ $$=$1; clicon_debug(2,"desc-schema-nodeid-strs-> desc-schema-nodeid-str"); }
;
desc_schema_nodeid_str : desc_schema_nodeid
{ $$=$1; clicon_debug(2,"descendant-schema-nodeid-str -> descendant-schema-nodeid"); }
| '"' desc_schema_nodeid '"'
{ $$=$2; clicon_debug(2,"descendant-schema-node-str -> descendant-node"); }
{ $$=$2; clicon_debug(2,"descendant-schema-nodeid-str -> descendant-schema-nodeid"); }
;
/* descendant-schema-nodeid */
desc_schema_nodeid : node_identifier
{ $$= $1; clicon_debug(2,"descendant-schema-nodeid -> node_identifier"); }
| node_identifier abs_schema_nodeid

View file

@ -220,7 +220,8 @@ ys_resolve_type(yang_stmt *ys,
/* Recursively resolve ys -> resolve with restrictions(options, etc)
* Note that the resolved type could be ys itself.
*/
if (yang_type_resolve((yang_stmt*)ys->ys_parent, ys, &resolved,
if (yang_type_resolve((yang_stmt*)ys->ys_parent, (yang_stmt*)ys->ys_parent,
ys, &resolved,
&options, &cvv, &pattern, &fraction) < 0)
goto done;
@ -328,7 +329,7 @@ cv2yang_type(enum cv_type cv_type)
* to find special cligen types such as ipv4addr.
* not true yang types
* @param[in] origtype Name of original type
* @param[in] restype Resolved type. may be null, in that case origtype is used
* @param[in] restype Resolved type. May be null, in that case origtype is used
* @param[out] cvtype Translation from resolved type
* @note Thereis a kludge for handling direct translations of native cligen types
*/
@ -343,7 +344,7 @@ clicon_type2cv(char *origtype,
if (restype != NULL){
yang2cv_type(restype, cvtype);
if (*cvtype == CGV_ERR){
clicon_err(OE_DB, 0, "\"%s\" type not translated", restype);
clicon_err(OE_YANG, EINVAL, "\"%s\" type not translated", restype);
goto done;
}
}
@ -354,7 +355,7 @@ clicon_type2cv(char *origtype,
*/
yang2cv_type(origtype, cvtype);
if (*cvtype == CGV_ERR){
clicon_err(OE_DB, 0, "\"%s\": type not resolved", origtype);
clicon_err(OE_YANG, EINVAL, "\"%s\": type not resolved", origtype);
goto done;
}
}
@ -601,7 +602,7 @@ ys_cv_validate_union_one(yang_stmt *ys,
enum cv_type cvtype;
cg_var *cvt=NULL;
if (yang_type_resolve(ys, yt, &yrt, &options, &cvv, &pattern,
if (yang_type_resolve(ys, ys, yt, &yrt, &options, &cvv, &pattern,
&fraction) < 0)
goto done;
restype = yrt?yrt->ys_argument:NULL;
@ -888,7 +889,8 @@ resolve_restrictions(yang_stmt *yrange,
}
/*! Recursively resolve a yang type to built-in type with optional restrictions
* @param[in] ys (original) type yang-stmt where the current search is based
* @param[in] yorig (original) type yang-stmt where original search is based
* @param[in] ys (transitive) yang-stmt where current search is based
* @param[in] ytype yang-stmt object containing currently resolving type
* @param[out] yrestype resolved type. return built-in type or NULL. mandatory
* @param[out] options pointer to flags field of optional values. optional
@ -906,7 +908,8 @@ resolve_restrictions(yang_stmt *yrange,
* Note also that for all pointer arguments, if NULL is given, no value is assigned.
*/
int
yang_type_resolve(yang_stmt *ys,
yang_type_resolve(yang_stmt *yorig,
yang_stmt *ys,
yang_stmt *ytype,
yang_stmt **yrestype,
int *options,
@ -938,6 +941,7 @@ yang_type_resolve(yang_stmt *ys,
goto done;
goto ok;
}
/* Resolving type restrictions */
yrange = yang_find((yang_node*)ytype, Y_RANGE, NULL);
ylength = yang_find((yang_node*)ytype, Y_LENGTH, NULL);
ypattern = yang_find((yang_node*)ytype, Y_PATTERN, NULL);
@ -955,11 +959,12 @@ yang_type_resolve(yang_stmt *ys,
if (prefix){ /* Go to top and find import that matches */
if ((yrmod = yang_find_module_by_prefix(ytype, prefix)) == NULL){
clicon_err(OE_DB, 0, "Type not resolved: \"%s:%s\" in module %s",
prefix, type, ys_module(ys)->ys_argument);
prefix, type, ys_module(yorig)->ys_argument);
goto done;
}
if ((rytypedef = yang_find((yang_node*)yrmod, Y_TYPEDEF, type)) == NULL)
goto ok; /* unresolved */
ys = rytypedef;
}
else
while (1){
@ -984,7 +989,7 @@ yang_type_resolve(yang_stmt *ys,
goto done;
}
/* recursively resolve this new type */
if (yang_type_resolve(ys, rytype, yrestype,
if (yang_type_resolve(yorig, ys, rytype, yrestype,
options, cvv, pattern, fraction) < 0)
goto done;
/* overwrites the resolved if any */
@ -1060,7 +1065,7 @@ yang_type_get(yang_stmt *ys,
type = yarg_id(ytype);
if (origtype)
*origtype = type;
if (yang_type_resolve(ys, ytype, yrestype,
if (yang_type_resolve(ys, ys, ytype, yrestype,
options, cvv, pattern, fraction) < 0)
goto done;
clicon_debug(3, "%s: %s %s->%s", __FUNCTION__, ys->ys_argument, type,