Fixed again: [Nested YANG choice does not work #342](https://github.com/clicon/clixon/issues/342)
Previous fix only for some sub-cases. New fix should work for all reecursive cases
This commit is contained in:
parent
657ddf9e87
commit
9537596a67
3 changed files with 128 additions and 82 deletions
|
|
@ -426,7 +426,7 @@ usage(clicon_handle h,
|
|||
"\t-m <mode>\tSpecify plugin syntax mode\n"
|
||||
"\t-q \t\tQuiet mode, dont print greetings or prompt, terminate on ctrl-C\n"
|
||||
"\t-p <dir>\tYang directory path (see CLICON_YANG_DIR)\n"
|
||||
"\t-G \t\tPrint auo-cli CLI syntax generated from YANG\n"
|
||||
"\t-G \t\tPrint auto-cli CLI syntax generated from YANG\n"
|
||||
"\t-L \t\tDebug print dynamic CLI syntax including completions and expansions\n"
|
||||
"\t-l <s|e|o|n|f<file>> \tLog on (s)yslog, std(e)rr, std(o)ut, (n)one or (f)ile (stderr is default)\n"
|
||||
"\t-y <file>\tOverride yang spec file (dont include .yang suffix)\n"
|
||||
|
|
|
|||
|
|
@ -274,58 +274,66 @@ check_when_condition(cxobj *x0p,
|
|||
goto done;
|
||||
}
|
||||
|
||||
/*! Given choice/case, remove all other cases.
|
||||
/*! Get cloxest yang case and choice, if any
|
||||
*/
|
||||
static int
|
||||
choice_delete_existing_children(cxobj *x0,
|
||||
yang_stmt *y1c,
|
||||
yang_stmt *y1case,
|
||||
yang_stmt *y1choice)
|
||||
choice_case_get(yang_stmt *yc,
|
||||
yang_stmt **ycase,
|
||||
yang_stmt **ychoice)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *x0c;
|
||||
yang_stmt *y0c;
|
||||
yang_stmt *y0case;
|
||||
yang_stmt *y0choice;
|
||||
cxobj *x0prev;
|
||||
yang_stmt *y0p;
|
||||
|
||||
/* Now traverse existing tree and compare with choice yang structure of added tree */
|
||||
x0prev = NULL;
|
||||
x0c = NULL;
|
||||
while ((x0c = xml_child_each(x0, x0c, CX_ELMNT)) != NULL) {
|
||||
if ((y0c = xml_spec(x0c)) == NULL ||
|
||||
yang_parent_get(y0c) == NULL){
|
||||
x0prev = x0c;
|
||||
continue;
|
||||
}
|
||||
y0p = yang_parent_get(y0c);
|
||||
if (yang_keyword_get(y0p) == Y_CASE){
|
||||
y0case = y0p;
|
||||
y0choice = yang_parent_get(y0case);
|
||||
}
|
||||
else if (yang_keyword_get(y0p) == Y_CHOICE){
|
||||
y0case = NULL;
|
||||
y0choice = y0p;
|
||||
}
|
||||
else{
|
||||
x0prev = x0c;
|
||||
continue;
|
||||
}
|
||||
if (y0choice == y1choice){
|
||||
if ((y0case == NULL && y0c != y1c) ||
|
||||
y0case != y1case){
|
||||
if (xml_purge(x0c) < 0)
|
||||
goto done;
|
||||
x0c = x0prev;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
x0prev = x0c;
|
||||
yang_stmt *yp;
|
||||
|
||||
if ((yp = yang_parent_get(yc)) == NULL)
|
||||
return 0;
|
||||
if (yang_keyword_get(yp) == Y_CASE){
|
||||
*ycase = yp;
|
||||
*ychoice = yang_parent_get(yp);
|
||||
return 1;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
else if (yang_keyword_get(yp) == Y_CHOICE){
|
||||
*ycase = NULL;
|
||||
*ychoice = yp;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Check if x0/y0 is part of other choice/case than y1 recursively , if so purge
|
||||
* @retval 0 No, y0 it is not in other case than y1
|
||||
* @retval 1 yes, y0 is in other case than y1
|
||||
*/
|
||||
static int
|
||||
choice_is_other(yang_stmt *y0c,
|
||||
yang_stmt *y0case,
|
||||
yang_stmt *y0choice,
|
||||
yang_stmt *y1c,
|
||||
yang_stmt *y1case,
|
||||
yang_stmt *y1choice)
|
||||
{
|
||||
yang_stmt *ycase;
|
||||
yang_stmt *ychoice;
|
||||
|
||||
if (y0choice == y1choice){
|
||||
if ((y0case == NULL && y0c != y1c) ||
|
||||
y0case != y1case){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* First recurse y0 */
|
||||
if (choice_case_get(y0choice, &ycase, &ychoice)){
|
||||
if (choice_is_other(y0choice, ycase, ychoice,
|
||||
y1c, y1case, y1choice) == 1)
|
||||
return 1;
|
||||
}
|
||||
/* Second recurse y1 */
|
||||
if (choice_case_get(y1choice, &ycase, &ychoice)){
|
||||
if (choice_is_other(y0choice, y0case, y0choice,
|
||||
y1choice, ycase, ychoice) == 1)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Check if choice nodes and implicitly remove all other cases.
|
||||
|
|
@ -346,31 +354,41 @@ choice_delete_existing_children(cxobj *x0,
|
|||
* other cases inside the choice.
|
||||
*/
|
||||
static int
|
||||
check_delete_existing_case(cxobj *x0,
|
||||
yang_stmt *y1c)
|
||||
choice_delete_other(cxobj *x0,
|
||||
yang_stmt *y1c)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *yp;
|
||||
yang_stmt *y1case;
|
||||
yang_stmt *y1choice;
|
||||
|
||||
if ((yp = yang_parent_get(y1c)) == NULL)
|
||||
cxobj *x0c;
|
||||
cxobj *x0prev;
|
||||
yang_stmt *y0c;
|
||||
yang_stmt *y0case;
|
||||
yang_stmt *y0choice;
|
||||
yang_stmt *y1case = NULL;
|
||||
yang_stmt *y1choice = NULL;
|
||||
|
||||
if (choice_case_get(y1c, &y1case, &y1choice) == 0)
|
||||
goto ok;
|
||||
if (yang_keyword_get(yp) == Y_CASE){
|
||||
y1case = yp;
|
||||
y1choice = yang_parent_get(y1case);
|
||||
x0prev = NULL;
|
||||
x0c = NULL;
|
||||
while ((x0c = xml_child_each(x0, x0c, CX_ELMNT)) != NULL) {
|
||||
if ((y0c = xml_spec(x0c)) == NULL ||
|
||||
yang_parent_get(y0c) == NULL){
|
||||
x0prev = x0c;
|
||||
continue;
|
||||
}
|
||||
if (choice_case_get(y0c, &y0case, &y0choice) == 0){
|
||||
x0prev = x0c;
|
||||
continue;
|
||||
}
|
||||
/* Check if x0/y0 is part of other choice/case than y1 recursively , if so purge */
|
||||
if (choice_is_other(y0c, y0case, y0choice, y1c, y1case, y1choice) == 1){
|
||||
if (xml_purge(x0c) < 0)
|
||||
goto done;
|
||||
x0c = x0prev;
|
||||
continue;
|
||||
}
|
||||
x0prev = x0c;
|
||||
}
|
||||
else if (yang_keyword_get(yp) == Y_CHOICE){
|
||||
y1case = NULL;
|
||||
y1choice = yp;
|
||||
}
|
||||
else
|
||||
goto ok;
|
||||
if (choice_delete_existing_children(x0, y1c, y1case, y1choice) < 0)
|
||||
goto done;
|
||||
/* Recursive call */
|
||||
if (check_delete_existing_case(x0, y1choice) < 0)
|
||||
goto done;
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
@ -827,8 +845,8 @@ text_modify(clicon_handle h,
|
|||
x1cname, yang_find_mynamespace(y0));
|
||||
goto done;
|
||||
}
|
||||
/* Check if existing case should be deleted */
|
||||
if (check_delete_existing_case(x0, yc) < 0)
|
||||
/* Check if existing choice/case should be deleted */
|
||||
if (choice_delete_other(x0, yc) < 0)
|
||||
goto done;
|
||||
/* See if there is a corresponding node in the base tree */
|
||||
x0c = NULL;
|
||||
|
|
|
|||
|
|
@ -40,12 +40,16 @@ module system{
|
|||
choice top{
|
||||
case topA {
|
||||
choice A{
|
||||
leaf A1x{
|
||||
case A1{
|
||||
leaf A1x{
|
||||
type string;
|
||||
}
|
||||
leaf A2x{
|
||||
}
|
||||
}
|
||||
case A2{
|
||||
leaf A2x{
|
||||
type string;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
leaf Ay{
|
||||
type string;
|
||||
|
|
@ -112,17 +116,41 @@ fi
|
|||
new "wait backend"
|
||||
wait_backend
|
||||
|
||||
new "cli set 2nd A stmt"
|
||||
expectpart "$($clixon_cli -1 -f $cfg -l o set c Ay foo)" 0 "^$"
|
||||
new "cli set 1st A stmt"
|
||||
expectpart "$($clixon_cli -1 -f $cfg -l o set c A1x aaa)" 0 "^$"
|
||||
|
||||
new "show config"
|
||||
expectpart "$($clixon_cli -1 -f $cfg -l o show config)" 0 "^<c xmlns=\"urn:example:config\"><Ay>foo</Ay></c>$"
|
||||
expectpart "$($clixon_cli -1 -f $cfg -l o show config)" 0 "^<c xmlns=\"urn:example:config\"><A1x>aaa</A1x></c>$"
|
||||
|
||||
new "cli set 2nd A stmt"
|
||||
expectpart "$($clixon_cli -1 -f $cfg -l o set c A2x bbb)" 0 "^$"
|
||||
|
||||
new "show config, only A2x"
|
||||
expectpart "$($clixon_cli -1 -f $cfg -l o show config)" 0 "^<c xmlns=\"urn:example:config\"><A2x>bbb</A2x></c>$"
|
||||
|
||||
new "cli set 3rd A stmt"
|
||||
expectpart "$($clixon_cli -1 -f $cfg -l o set c Ay ccc)" 0 "^$"
|
||||
|
||||
new "show config: A2x + Ay"
|
||||
expectpart "$($clixon_cli -1 -f $cfg -l o show config)" 0 "^<c xmlns=\"urn:example:config\"><A2x>bbb</A2x><Ay>ccc</Ay></c>$"
|
||||
|
||||
new "cli set 1st B stmt"
|
||||
expectpart "$($clixon_cli -1 -f $cfg -l o set c B1x bar)" 0 "^$"
|
||||
expectpart "$($clixon_cli -1 -f $cfg -l o set c B1x ddd)" 0 "^$"
|
||||
|
||||
new "show config, Ay removed"
|
||||
expectpart "$($clixon_cli -1 -f $cfg -l o show config)" 0 "^<c xmlns=\"urn:example:config\"><B1x>bar</B1x></c>$" --not-- "<Ay>foo</Ay>"
|
||||
new "show config: B1x"
|
||||
expectpart "$($clixon_cli -1 -f $cfg -l o show config)" 0 "^<c xmlns=\"urn:example:config\"><B1x>ddd</B1x></c>$"
|
||||
|
||||
new "cli set 3rd A stmt"
|
||||
expectpart "$($clixon_cli -1 -f $cfg -l o set c Ay ccc)" 0 "^$"
|
||||
|
||||
new "show config: Ay"
|
||||
expectpart "$($clixon_cli -1 -f $cfg -l o show config)" 0 "^<c xmlns=\"urn:example:config\"><Ay>ccc</Ay></c>$"
|
||||
|
||||
new "cli set 3rd B stmt"
|
||||
expectpart "$($clixon_cli -1 -f $cfg -l o set c By fff)" 0 "^$"
|
||||
|
||||
new "show config: By"
|
||||
expectpart "$($clixon_cli -1 -f $cfg -l o show config)" 0 "^<c xmlns=\"urn:example:config\"><By>fff</By></c>$"
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
new "Kill backend"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue