[yang type range statement does not support multiple values](https://github.com/clicon/clixon/issues/59)

[Multiple ranges support](https://github.com/clicon/clixon/issues/78)
Restructured "cb" parameter in cli_generate.c
This commit is contained in:
Olof hagsand 2019-03-04 14:36:43 +01:00
parent fc93051b87
commit b182e8666f
6 changed files with 274 additions and 161 deletions

View file

@ -7,10 +7,8 @@
### Major New features ### Major New features
* New backend startup and upgrade support, see [doc/startup.md] for details * New backend startup and upgrade support, see [doc/startup.md] for details
* Enable with CLICON_XMLDB_MODSTATE config option * Enable with CLICON_XMLDB_MODSTATE config option
* Tag all datastores with system modules-state as in RFC7895
* Check modules-state tags when loading a datastore at startup * Check modules-state tags when loading a datastore at startup
* Check which modules match, and which do not. * Check which modules match, and which do not.
* Loading of a "startup" XML or JSON configuration
* Loading of "extra" XML. * Loading of "extra" XML.
* Detection of in-compatible XML and Yang models in the startup configuration. * Detection of in-compatible XML and Yang models in the startup configuration.
* An upgrade callback when in-compatible XML is encountered (`ca_upgrade`) * An upgrade callback when in-compatible XML is encountered (`ca_upgrade`)
@ -31,6 +29,9 @@
* Added libgen.h for baseline() * Added libgen.h for baseline()
### Corrected Bugs ### Corrected Bugs
* [yang type range statement does not support multiple values](https://github.com/clicon/clixon/issues/59)
* Remaining problem was mainly CLIgen feature. Strengthened test cases in [test/test_type.sh].
* Also in: [Multiple ranges support](https://github.com/clicon/clixon/issues/78)
* Fixed numeric ordering of lists (again) [https://github.com/clicon/clixon/issues/64] It was previously just fixed for leaf-lists. * Fixed numeric ordering of lists (again) [https://github.com/clicon/clixon/issues/64] It was previously just fixed for leaf-lists.
* There was a problem with ordered-by-user for XML children that appeared in some circumstances and difficult to trigger. Entries entered by the user did not appear in the order they were entered. This should now be fixed. * There was a problem with ordered-by-user for XML children that appeared in some circumstances and difficult to trigger. Entries entered by the user did not appear in the order they were entered. This should now be fixed.

View file

@ -103,9 +103,9 @@ Jan 2 11:17:58: yang2cli: buf
* @param[in] h clicon handle * @param[in] h clicon handle
* @param[in] ys yang_stmt of the node at hand * @param[in] ys yang_stmt of the node at hand
* @param[in] cvtype Type of the cligen variable * @param[in] cvtype Type of the cligen variable
* @param[in] cb0 The string where the result format string is inserted.
* @param[in] options * @param[in] options
* @param[in] fraction_digits * @param[in] fraction_digits
* @param[out] cb The string where the result format string is inserted.
* @see expand_dbvar This is where the expand string is used * @see expand_dbvar This is where the expand string is used
* @note XXX only fraction_digits handled,should also have mincv, maxcv, pattern * @note XXX only fraction_digits handled,should also have mincv, maxcv, pattern
@ -114,20 +114,20 @@ static int
cli_expand_var_generate(clicon_handle h, cli_expand_var_generate(clicon_handle h,
yang_stmt *ys, yang_stmt *ys,
enum cv_type cvtype, enum cv_type cvtype,
cbuf *cb0,
int options, int options,
uint8_t fraction_digits) uint8_t fraction_digits,
cbuf *cb)
{ {
int retval = -1; int retval = -1;
char *api_path_fmt = NULL; char *api_path_fmt = NULL;
if (yang2api_path_fmt(ys, 1, &api_path_fmt) < 0) if (yang2api_path_fmt(ys, 1, &api_path_fmt) < 0)
goto done; goto done;
cprintf(cb0, "|<%s:%s", ys->ys_argument, cprintf(cb, "|<%s:%s", ys->ys_argument,
cv_type2str(cvtype)); cv_type2str(cvtype));
if (options & YANG_OPTIONS_FRACTION_DIGITS) if (options & YANG_OPTIONS_FRACTION_DIGITS)
cprintf(cb0, " fraction-digits:%u", fraction_digits); cprintf(cb, " fraction-digits:%u", fraction_digits);
cprintf(cb0, " %s(\"candidate\",\"%s\")>", cprintf(cb, " %s(\"candidate\",\"%s\")>",
GENERATE_EXPAND_XMLDB, GENERATE_EXPAND_XMLDB,
api_path_fmt); api_path_fmt);
retval = 0; retval = 0;
@ -140,21 +140,21 @@ cli_expand_var_generate(clicon_handle h,
/*! Create callback with api_path format string as argument /*! Create callback with api_path format string as argument
* @param[in] h clicon handle * @param[in] h clicon handle
* @param[in] ys yang_stmt of the node at hand * @param[in] ys yang_stmt of the node at hand
* @param[in] cb0 The string where the result format string is inserted. * @param[out] cb The string where the result format string is inserted.
* @see cli_dbxml This is where the xmlkeyfmt string is used * @see cli_dbxml This is where the xmlkeyfmt string is used
* @see pt_callback_reference in CLIgen where the actual callback overwrites the template * @see pt_callback_reference in CLIgen where the actual callback overwrites the template
*/ */
static int static int
cli_callback_generate(clicon_handle h, cli_callback_generate(clicon_handle h,
yang_stmt *ys, yang_stmt *ys,
cbuf *cb0) cbuf *cb)
{ {
int retval = -1; int retval = -1;
char *api_path_fmt = NULL; char *api_path_fmt = NULL;
if (yang2api_path_fmt(ys, 0, &api_path_fmt) < 0) if (yang2api_path_fmt(ys, 0, &api_path_fmt) < 0)
goto done; goto done;
cprintf(cb0, ",%s(\"%s\")", GENERATE_CALLBACK, cprintf(cb, ",%s(\"%s\")", GENERATE_CALLBACK,
api_path_fmt); api_path_fmt);
retval = 0; retval = 0;
done: done:
@ -213,40 +213,57 @@ yang2cli_var_identityref(yang_stmt *ys,
} }
/*! Generate range check statements for CLI variables /*! Generate range check statements for CLI variables
* @param[in] ys Yang statement
* @param[in] options Flags field of optional values, eg YANG_OPTIONS_RANGE
* @param[in] cvv Cvec with array of range_min/range_max cv:s (if YANG_OPTIONS_RANGE is set in options)
* @param[out] cb Buffer where cligen code is written * @param[out] cb Buffer where cligen code is written
* @see yang2cli_var_sub Its sub-function * @see yang2cli_var_sub which is the main function
* In yang ranges are given as range 1 or range 1 .. 16, encoded in a cvv
* 0 : range_min = x
* and
* 0 : range_min = x
* 1 : range_max = y
* Multiple ranges are given as: range x..y | x1..y1
* This is encode in clixon as a cvec as:
* 0 : range_min = x
* 1 : range_max = y
* 0 : range_min = x1
* 1 : range_max = y1
*
* Generation of cli code
* Single range is made by eg:
* <n:uint8 range[1:16]>
* Multiple ranges is made by generating code eg:
* <n:uint8 range[1:16] range[32:64]>
*/ */
static int static int
yang2cli_var_range(yang_stmt *ys, yang2cli_var_range(yang_stmt *ys,
cvec *cvv,
int options, int options,
cvec *cvv,
cbuf *cb) cbuf *cb)
{ {
int retval = -1; int retval = -1;
int i; int i;
cg_var *cv; cg_var *cv1; /* lower limit */
cg_var *cv2; /* upper limit */
/* Loop through range_min and range_min..range_max */ /* Loop through range_min and range_min..range_max */
i = 0; i = 0;
while (i<cvec_len(cvv)){ while (i<cvec_len(cvv)){
if (i){ cv1 = cvec_i(cvv, i++);
// clicon_log(LOG_NOTICE, "%s: Warning %s has more ranges, ignoring", __FUNCTION__, ys->ys_argument); if (strcmp(cv_name_get(cv1),"range_min") == 0){
break;
}
cv = cvec_i(cvv, i++);
if (strcmp(cv_name_get(cv),"range_min") == 0){
cprintf(cb, " %s[", (options&YANG_OPTIONS_RANGE)?"range":"length"); cprintf(cb, " %s[", (options&YANG_OPTIONS_RANGE)?"range":"length");
cv2cbuf(cv, cb); cv2cbuf(cv1, cb);
cprintf(cb,":"); cprintf(cb,":");
/* probe next */ /* probe next */
if (i<cvec_len(cvv) && if (i<cvec_len(cvv) &&
(cv = cvec_i(cvv, i)) != NULL && (cv2 = cvec_i(cvv, i)) != NULL &&
strcmp(cv_name_get(cv),"range_max") == 0){ strcmp(cv_name_get(cv2),"range_max") == 0){
i++; i++;
cv2cbuf(cv, cb); cv2cbuf(cv2, cb);
} }
else /* If not, it is a single number range [x:x]*/ else /* If not, it is a single number range [x:x]*/
cv2cbuf(cv, cb); cv2cbuf(cv1, cb);
cprintf(cb,"]"); cprintf(cb,"]");
} }
} }
@ -256,11 +273,11 @@ yang2cli_var_range(yang_stmt *ys,
} }
/* Forward */ /* Forward */
static int yang2cli_stmt(clicon_handle h, yang_stmt *ys, cbuf *cb, static int yang2cli_stmt(clicon_handle h, yang_stmt *ys,
enum genmodel_type gt, int level); enum genmodel_type gt, int level, cbuf *cb);
static int yang2cli_var_union(clicon_handle h, yang_stmt *ys, char *origtype, static int yang2cli_var_union(clicon_handle h, yang_stmt *ys, char *origtype,
yang_stmt *ytype, cbuf *cb, char *helptext); yang_stmt *ytype, char *helptext, cbuf *cb);
/*! Generate CLI code for Yang leaf statement to CLIgen variable of specific type /*! Generate CLI code for Yang leaf statement to CLIgen variable of specific type
* Check for completion (of already existent values), ranges (eg range[min:max]) and * Check for completion (of already existent values), ranges (eg range[min:max]) and
@ -268,20 +285,26 @@ static int yang2cli_var_union(clicon_handle h, yang_stmt *ys, char *origtype,
* @param[in] h Clixon handle * @param[in] h Clixon handle
* @param[in] ys Yang statement * @param[in] ys Yang statement
* @param[in] ytype Yang union type being resolved * @param[in] ytype Yang union type being resolved
* @param[out] cb Buffer where cligen code is written
* @param[in] helptext CLI help text * @param[in] helptext CLI help text
* @param[in] cvtype
* @param[in] options Flags field of optional values, see YANG_OPTIONS_*
* @param[in] cvv Cvec with array of range_min/range_max cv:s
* @param[in] pattern String of POSIX regexp pattern
* @param[in] fraction for decimal64, how many digits after period
* @param[out] cb Buffer where cligen code is written
* @see yang_type_resolve for options and other arguments
*/ */
static int static int
yang2cli_var_sub(clicon_handle h, yang2cli_var_sub(clicon_handle h,
yang_stmt *ys, yang_stmt *ys,
yang_stmt *ytype, /* resolved type */ yang_stmt *ytype, /* resolved type */
cbuf *cb,
char *helptext, char *helptext,
enum cv_type cvtype, enum cv_type cvtype,
int options, int options,
cvec *cvv, cvec *cvv,
char *pattern, char *pattern,
uint8_t fraction_digits uint8_t fraction_digits,
cbuf *cb
) )
{ {
int retval = -1; int retval = -1;
@ -296,6 +319,7 @@ yang2cli_var_sub(clicon_handle h,
} }
type = ytype?ytype->ys_argument:NULL; type = ytype?ytype->ys_argument:NULL;
cvtypestr = cv_type2str(cvtype); cvtypestr = cv_type2str(cvtype);
if (type && strcmp(type, "identityref") == 0) if (type && strcmp(type, "identityref") == 0)
cprintf(cb, "("); cprintf(cb, "(");
cprintf(cb, "<%s:%s", ys->ys_argument, cvtypestr); cprintf(cb, "<%s:%s", ys->ys_argument, cvtypestr);
@ -323,7 +347,7 @@ yang2cli_var_sub(clicon_handle h,
cprintf(cb, " fraction-digits:%u", fraction_digits); cprintf(cb, " fraction-digits:%u", fraction_digits);
if (options & (YANG_OPTIONS_RANGE|YANG_OPTIONS_LENGTH)){ if (options & (YANG_OPTIONS_RANGE|YANG_OPTIONS_LENGTH)){
if (yang2cli_var_range(ys, cvv, options, cb) < 0) if (yang2cli_var_range(ys, options, cvv, cb) < 0)
goto done; goto done;
} }
if (options & YANG_OPTIONS_PATTERN){ if (options & YANG_OPTIONS_PATTERN){
@ -358,8 +382,8 @@ yang2cli_var_union_one(clicon_handle h,
yang_stmt *ys, yang_stmt *ys,
char *origtype, char *origtype,
yang_stmt *ytsub, yang_stmt *ytsub,
cbuf *cb, char *helptext,
char *helptext) cbuf *cb)
{ {
int retval = -1; int retval = -1;
int options = 0; int options = 0;
@ -378,14 +402,14 @@ yang2cli_var_union_one(clicon_handle h,
restype = ytype?ytype->ys_argument:NULL; restype = ytype?ytype->ys_argument:NULL;
if (restype && strcmp(restype, "union") == 0){ /* recursive union */ if (restype && strcmp(restype, "union") == 0){ /* recursive union */
if (yang2cli_var_union(h, ys, origtype, ytype, cb, helptext) < 0) if (yang2cli_var_union(h, ys, origtype, ytype, helptext, cb) < 0)
goto done; goto done;
} }
else { else {
if (clicon_type2cv(origtype, restype, ys, &cvtype) < 0) if (clicon_type2cv(origtype, restype, ys, &cvtype) < 0)
goto done; goto done;
if ((retval = yang2cli_var_sub(h, ys, ytype, cb, helptext, cvtype, if ((retval = yang2cli_var_sub(h, ys, ytype, helptext, cvtype,
options, cvv, pattern, fraction_digits)) < 0) options, cvv, pattern, fraction_digits, cb)) < 0)
goto done; goto done;
} }
retval = 0; retval = 0;
@ -399,17 +423,16 @@ yang2cli_var_union_one(clicon_handle h,
* @param[in] ys Yang statement (caller) * @param[in] ys Yang statement (caller)
* @param[in] origtype Name of original type in the call * @param[in] origtype Name of original type in the call
* @param[in] ytype Yang resolved type (a union in this case) * @param[in] ytype Yang resolved type (a union in this case)
* @param[in] type Name of type
* @param[in] cb Buffer where cligen code is written
* @param[in] helptext CLI help text * @param[in] helptext CLI help text
* @param[out] cb Buffer where cligen code is written
*/ */
static int static int
yang2cli_var_union(clicon_handle h, yang2cli_var_union(clicon_handle h,
yang_stmt *ys, yang_stmt *ys,
char *origtype, char *origtype,
yang_stmt *ytype, yang_stmt *ytype,
cbuf *cb, char *helptext,
char *helptext) cbuf *cb)
{ {
int retval = -1; int retval = -1;
yang_stmt *ytsub = NULL; yang_stmt *ytsub = NULL;
@ -425,7 +448,7 @@ yang2cli_var_union(clicon_handle h,
continue; continue;
if (i++) if (i++)
cprintf(cb, "|"); cprintf(cb, "|");
if (yang2cli_var_union_one(h, ys, origtype, ytsub, cb, helptext) < 0) if (yang2cli_var_union_one(h, ys, origtype, ytsub, helptext, cb) < 0)
goto done; goto done;
} }
retval = 0; retval = 0;
@ -436,18 +459,21 @@ yang2cli_var_union(clicon_handle h,
/*! Generate CLI code for Yang leaf statement to CLIgen variable /*! Generate CLI code for Yang leaf statement to CLIgen variable
* @param[in] h Clixon handle * @param[in] h Clixon handle
* @param[in] ys Yang statement * @param[in] ys Yang statement
* @param[in] cb Buffer where cligen code is written
* @param[in] helptext CLI help text * @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>. * 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 sub-types. * One complication is yang union, that needs a recursion since it consists of
* sub-types.
* eg type union{ type int32; type string } --> (<x:int32>| <x:string>) * eg type union{ type int32; type string } --> (<x:int32>| <x:string>)
* Another is multiple ranges
*/ */
static int static int
yang2cli_var(clicon_handle h, yang2cli_var(clicon_handle h,
yang_stmt *ys, yang_stmt *ys,
cbuf *cb, char *helptext,
char *helptext) cbuf *cb)
{ {
int retval = -1; int retval = -1;
char *origtype; char *origtype;
@ -476,11 +502,11 @@ yang2cli_var(clicon_handle h,
if (restype && strcmp(restype, "union") == 0){ if (restype && strcmp(restype, "union") == 0){
/* Union: loop over resolved type's sub-types (can also be recursive unions) */ /* Union: loop over resolved type's sub-types (can also be recursive unions) */
cprintf(cb, "("); cprintf(cb, "(");
if (yang2cli_var_union(h, ys, origtype, yrestype, cb, helptext) < 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, cb, if (cli_expand_var_generate(h, ys, cvtype,
options, fraction_digits) < 0) options, fraction_digits, cb) < 0)
goto done; goto done;
if (helptext) if (helptext)
cprintf(cb, "(\"%s\")", helptext); cprintf(cb, "(\"%s\")", helptext);
@ -498,12 +524,12 @@ yang2cli_var(clicon_handle h,
completionp = clicon_cli_genmodel_completion(h); completionp = clicon_cli_genmodel_completion(h);
if (completionp) if (completionp)
cprintf(cb, "("); cprintf(cb, "(");
if ((retval = yang2cli_var_sub(h, ys, yrestype, cb, helptext, cvtype, if ((retval = yang2cli_var_sub(h, ys, yrestype, helptext, cvtype,
options, cvv, pattern, fraction_digits)) < 0) options, cvv, pattern, fraction_digits, cb)) < 0)
goto done; goto done;
if (completionp){ if (completionp){
if (cli_expand_var_generate(h, ys, cvtype, cb, if (cli_expand_var_generate(h, ys, cvtype,
options, fraction_digits) < 0) options, fraction_digits, cb) < 0)
goto done; goto done;
if (helptext) if (helptext)
cprintf(cb, "(\"%s\")", helptext); cprintf(cb, "(\"%s\")", helptext);
@ -518,18 +544,18 @@ yang2cli_var(clicon_handle h,
/*! Generate CLI code for Yang leaf statement /*! Generate CLI code for Yang leaf statement
* @param[in] h Clixon handle * @param[in] h Clixon handle
* @param[in] ys Yang statement * @param[in] ys Yang statement
* @param[in] cbuf Buffer where cligen code is written
* @param[in] gt CLI Generate style * @param[in] gt CLI Generate style
* @param[in] level Indentation level * @param[in] level Indentation level
* @param[in] callback If set, include a "; cli_set()" callback, otherwise not. * @param[in] callback If set, include a "; cli_set()" callback, otherwise not
* @param[out] cb Buffer where cligen code is written
*/ */
static int static int
yang2cli_leaf(clicon_handle h, yang2cli_leaf(clicon_handle h,
yang_stmt *ys, yang_stmt *ys,
cbuf *cbuf,
enum genmodel_type gt, enum genmodel_type gt,
int level, int level,
int callback) int callback,
cbuf *cb)
{ {
yang_stmt *yd; /* description */ yang_stmt *yd; /* description */
int retval = -1; int retval = -1;
@ -545,22 +571,22 @@ yang2cli_leaf(clicon_handle h,
if ((s = strstr(helptext, "\n\n")) != NULL) if ((s = strstr(helptext, "\n\n")) != NULL)
*s = '\0'; *s = '\0';
} }
cprintf(cbuf, "%*s", level*3, ""); cprintf(cb, "%*s", level*3, "");
if (gt == GT_VARS|| gt == GT_ALL){ if (gt == GT_VARS|| gt == GT_ALL){
cprintf(cbuf, "%s", ys->ys_argument); cprintf(cb, "%s", ys->ys_argument);
if (helptext) if (helptext)
cprintf(cbuf, "(\"%s\")", helptext); cprintf(cb, "(\"%s\")", helptext);
cprintf(cbuf, " "); cprintf(cb, " ");
if (yang2cli_var(h, ys, cbuf, helptext) < 0) if (yang2cli_var(h, ys, helptext, cb) < 0)
goto done; goto done;
} }
else else
if (yang2cli_var(h, ys, cbuf, helptext) < 0) if (yang2cli_var(h, ys, helptext, cb) < 0)
goto done; goto done;
if (callback){ if (callback){
if (cli_callback_generate(h, ys, cbuf) < 0) if (cli_callback_generate(h, ys, cb) < 0)
goto done; goto done;
cprintf(cbuf, ";\n"); cprintf(cb, ";\n");
} }
retval = 0; retval = 0;
@ -573,16 +599,16 @@ yang2cli_leaf(clicon_handle h,
/*! Generate CLI code for Yang container statement /*! Generate CLI code for Yang container statement
* @param[in] h Clixon handle * @param[in] h Clixon handle
* @param[in] ys Yang statement * @param[in] ys Yang statement
* @param[in] cbuf Buffer where cligen code is written
* @param[in] gt CLI Generate style * @param[in] gt CLI Generate style
* @param[in] level Indentation level * @param[in] level Indentation level
* @param[out] cb Buffer where cligen code is written
*/ */
static int static int
yang2cli_container(clicon_handle h, yang2cli_container(clicon_handle h,
yang_stmt *ys, yang_stmt *ys,
cbuf *cbuf,
enum genmodel_type gt, enum genmodel_type gt,
int level) int level,
cbuf *cb)
{ {
yang_stmt *yc; yang_stmt *yc;
yang_stmt *yd; yang_stmt *yd;
@ -591,7 +617,7 @@ yang2cli_container(clicon_handle h,
char *helptext = NULL; char *helptext = NULL;
char *s; char *s;
cprintf(cbuf, "%*s%s", level*3, "", ys->ys_argument); cprintf(cb, "%*s%s", level*3, "", ys->ys_argument);
if ((yd = yang_find((yang_node*)ys, Y_DESCRIPTION, NULL)) != NULL){ if ((yd = yang_find((yang_node*)ys, Y_DESCRIPTION, NULL)) != NULL){
if ((helptext = strdup(yd->ys_argument)) == NULL){ if ((helptext = strdup(yd->ys_argument)) == NULL){
clicon_err(OE_UNIX, errno, "strdup"); clicon_err(OE_UNIX, errno, "strdup");
@ -599,16 +625,16 @@ yang2cli_container(clicon_handle h,
} }
if ((s = strstr(helptext, "\n\n")) != NULL) if ((s = strstr(helptext, "\n\n")) != NULL)
*s = '\0'; *s = '\0';
cprintf(cbuf, "(\"%s\")", helptext); cprintf(cb, "(\"%s\")", helptext);
} }
if (cli_callback_generate(h, ys, cbuf) < 0) if (cli_callback_generate(h, ys, cb) < 0)
goto done; goto done;
cprintf(cbuf, ";{\n"); cprintf(cb, ";{\n");
for (i=0; i<ys->ys_len; i++) for (i=0; i<ys->ys_len; i++)
if ((yc = ys->ys_stmt[i]) != NULL) if ((yc = ys->ys_stmt[i]) != NULL)
if (yang2cli_stmt(h, yc, cbuf, gt, level+1) < 0) if (yang2cli_stmt(h, yc, gt, level+1, cb) < 0)
goto done; goto done;
cprintf(cbuf, "%*s}\n", level*3, ""); cprintf(cb, "%*s}\n", level*3, "");
retval = 0; retval = 0;
done: done:
if (helptext) if (helptext)
@ -619,16 +645,16 @@ yang2cli_container(clicon_handle h,
/*! Generate CLI code for Yang list statement /*! Generate CLI code for Yang list statement
* @param[in] h Clixon handle * @param[in] h Clixon handle
* @param[in] ys Yang statement * @param[in] ys Yang statement
* @param[in] cbuf Buffer where cligen code is written
* @param[in] gt CLI Generate style * @param[in] gt CLI Generate style
* @param[in] level Indentation level * @param[in] level Indentation level
* @param[out] cb Buffer where cligen code is written
*/ */
static int static int
yang2cli_list(clicon_handle h, yang2cli_list(clicon_handle h,
yang_stmt *ys, yang_stmt *ys,
cbuf *cbuf,
enum genmodel_type gt, enum genmodel_type gt,
int level) int level,
cbuf *cb)
{ {
yang_stmt *yc; yang_stmt *yc;
yang_stmt *yd; yang_stmt *yd;
@ -641,7 +667,7 @@ yang2cli_list(clicon_handle h,
char *helptext = NULL; char *helptext = NULL;
char *s; char *s;
cprintf(cbuf, "%*s%s", level*3, "", ys->ys_argument); cprintf(cb, "%*s%s", level*3, "", ys->ys_argument);
if ((yd = yang_find((yang_node*)ys, Y_DESCRIPTION, NULL)) != NULL){ if ((yd = yang_find((yang_node*)ys, Y_DESCRIPTION, NULL)) != NULL){
if ((helptext = strdup(yd->ys_argument)) == NULL){ if ((helptext = strdup(yd->ys_argument)) == NULL){
clicon_err(OE_UNIX, errno, "strdup"); clicon_err(OE_UNIX, errno, "strdup");
@ -649,7 +675,7 @@ yang2cli_list(clicon_handle h,
} }
if ((s = strstr(helptext, "\n\n")) != NULL) if ((s = strstr(helptext, "\n\n")) != NULL)
*s = '\0'; *s = '\0';
cprintf(cbuf, "(\"%s\")", helptext); cprintf(cb, "(\"%s\")", helptext);
} }
/* Loop over all key variables */ /* Loop over all key variables */
cvk = ys->ys_cvec; /* Use Y_LIST cache, see ys_populate_list() */ cvk = ys->ys_cvec; /* Use Y_LIST cache, see ys_populate_list() */
@ -665,12 +691,12 @@ yang2cli_list(clicon_handle h,
/* Print key variable now, and skip it in loop below /* Print key variable now, and skip it in loop below
Note, only print callback on last statement Note, only print callback on last statement
*/ */
if (yang2cli_leaf(h, yleaf, cbuf, gt==GT_VARS?GT_NONE:gt, level+1, if (yang2cli_leaf(h, yleaf, gt==GT_VARS?GT_NONE:gt, level+1,
cvec_next(cvk, cvi)?0:1) < 0) cvec_next(cvk, cvi)?0:1, cb) < 0)
goto done; goto done;
} }
cprintf(cbuf, "{\n"); cprintf(cb, "{\n");
for (i=0; i<ys->ys_len; i++) for (i=0; i<ys->ys_len; i++)
if ((yc = ys->ys_stmt[i]) != NULL){ if ((yc = ys->ys_stmt[i]) != NULL){
/* cvk is a cvec of strings containing variable names /* cvk is a cvec of strings containing variable names
@ -684,10 +710,10 @@ yang2cli_list(clicon_handle h,
} }
if (cvi != NULL) if (cvi != NULL)
continue; continue;
if (yang2cli_stmt(h, yc, cbuf, gt, level+1) < 0) if (yang2cli_stmt(h, yc, gt, level+1, cb) < 0)
goto done; goto done;
} }
cprintf(cbuf, "%*s}\n", level*3, ""); cprintf(cb, "%*s}\n", level*3, "");
retval = 0; retval = 0;
done: done:
if (helptext) if (helptext)
@ -699,9 +725,9 @@ yang2cli_list(clicon_handle h,
* *
* @param[in] h Clixon handle * @param[in] h Clixon handle
* @param[in] ys Yang statement * @param[in] ys Yang statement
* @param[in] cbuf Buffer where cligen code is written
* @param[in] gt CLI Generate style * @param[in] gt CLI Generate style
* @param[in] level Indentation level * @param[in] level Indentation level
* @param[out] cb Buffer where cligen code is written
@example @example
choice interface-type { choice interface-type {
container ethernet { ... } container ethernet { ... }
@ -714,9 +740,9 @@ yang2cli_list(clicon_handle h,
static int static int
yang2cli_choice(clicon_handle h, yang2cli_choice(clicon_handle h,
yang_stmt *ys, yang_stmt *ys,
cbuf *cbuf,
enum genmodel_type gt, enum genmodel_type gt,
int level) int level,
cbuf *cb)
{ {
int retval = -1; int retval = -1;
yang_stmt *yc; yang_stmt *yc;
@ -726,7 +752,7 @@ yang2cli_choice(clicon_handle h,
if ((yc = ys->ys_stmt[i]) != NULL){ if ((yc = ys->ys_stmt[i]) != NULL){
switch (yc->ys_keyword){ switch (yc->ys_keyword){
case Y_CASE: case Y_CASE:
if (yang2cli_stmt(h, yc, cbuf, gt, level+2) < 0) if (yang2cli_stmt(h, yc, gt, level+2, cb) < 0)
goto done; goto done;
break; break;
case Y_CONTAINER: case Y_CONTAINER:
@ -734,7 +760,7 @@ yang2cli_choice(clicon_handle h,
case Y_LEAF_LIST: case Y_LEAF_LIST:
case Y_LIST: case Y_LIST:
default: default:
if (yang2cli_stmt(h, yc, cbuf, gt, level+1) < 0) if (yang2cli_stmt(h, yc, gt, level+1, cb) < 0)
goto done; goto done;
break; break;
} }
@ -747,17 +773,16 @@ yang2cli_choice(clicon_handle h,
/*! Generate CLI code for Yang statement /*! Generate CLI code for Yang statement
* @param[in] h Clixon handle * @param[in] h Clixon handle
* @param[in] ys Yang statement * @param[in] ys Yang statement
* @param[in] cbuf Buffer where cligen code is written * @param[out] cb Buffer where cligen code is written
* @param[in] gt CLI Generate style * @param[in] gt CLI Generate style
* @param[in] level Indentation level * @param[in] level Indentation level
*/ */
static int static int
yang2cli_stmt(clicon_handle h, yang2cli_stmt(clicon_handle h,
yang_stmt *ys, yang_stmt *ys,
cbuf *cbuf,
enum genmodel_type gt, enum genmodel_type gt,
int level /* indentation level for pretty-print */ int level, /* indentation level for pretty-print */
) cbuf *cb)
{ {
yang_stmt *yc; yang_stmt *yc;
int retval = -1; int retval = -1;
@ -766,20 +791,20 @@ yang2cli_stmt(clicon_handle h,
if (yang_config(ys)){ if (yang_config(ys)){
switch (ys->ys_keyword){ switch (ys->ys_keyword){
case Y_CONTAINER: case Y_CONTAINER:
if (yang2cli_container(h, ys, cbuf, gt, level) < 0) if (yang2cli_container(h, ys, gt, level, cb) < 0)
goto done; goto done;
break; break;
case Y_LIST: case Y_LIST:
if (yang2cli_list(h, ys, cbuf, gt, level) < 0) if (yang2cli_list(h, ys, gt, level, cb) < 0)
goto done; goto done;
break; break;
case Y_CHOICE: case Y_CHOICE:
if (yang2cli_choice(h, ys, cbuf, gt, level) < 0) if (yang2cli_choice(h, ys, gt, level, cb) < 0)
goto done; goto done;
break; break;
case Y_LEAF_LIST: case Y_LEAF_LIST:
case Y_LEAF: case Y_LEAF:
if (yang2cli_leaf(h, ys, cbuf, gt, level, 1) < 0) if (yang2cli_leaf(h, ys, gt, level, 1, cb) < 0)
goto done; goto done;
break; break;
case Y_CASE: case Y_CASE:
@ -787,7 +812,7 @@ yang2cli_stmt(clicon_handle h,
case Y_MODULE: case Y_MODULE:
for (i=0; i<ys->ys_len; i++) for (i=0; i<ys->ys_len; i++)
if ((yc = ys->ys_stmt[i]) != NULL) if ((yc = ys->ys_stmt[i]) != NULL)
if (yang2cli_stmt(h, yc, cbuf, gt, level+1) < 0) if (yang2cli_stmt(h, yc, gt, level+1, cb) < 0)
goto done; goto done;
break; break;
default: /* skip */ default: /* skip */
@ -815,28 +840,28 @@ yang2cli(clicon_handle h,
parse_tree *ptnew, parse_tree *ptnew,
enum genmodel_type gt) enum genmodel_type gt)
{ {
cbuf *cbuf; cbuf *cb = NULL;
int i; int i;
int retval = -1; int retval = -1;
yang_stmt *ymod = NULL; yang_stmt *ymod = NULL;
cvec *globals; /* global variables from syntax */ cvec *globals; /* global variables from syntax */
if ((cbuf = cbuf_new()) == NULL){ if ((cb = cbuf_new()) == NULL){
clicon_err(OE_XML, errno, "cbuf_new"); clicon_err(OE_XML, errno, "cbuf_new");
goto done; goto done;
} }
/* Traverse YANG, loop through all modules and generate CLI */ /* Traverse YANG, loop through all modules and generate CLI */
for (i=0; i<yspec->yp_len; i++) for (i=0; i<yspec->yp_len; i++)
if ((ymod = yspec->yp_stmt[i]) != NULL){ if ((ymod = yspec->yp_stmt[i]) != NULL){
if (yang2cli_stmt(h, ymod, cbuf, gt, 0) < 0) if (yang2cli_stmt(h, ymod, gt, 0, cb) < 0)
goto done; goto done;
} }
clicon_debug(2, "%s: buf\n%s\n", __FUNCTION__, cbuf_get(cbuf)); clicon_debug(2, "%s: buf\n%s\n", __FUNCTION__, cbuf_get(cb));
/* Parse the buffer using cligen parser. XXX why this?*/ /* Parse the buffer using cligen parser. XXX why this?*/
if ((globals = cvec_new(0)) == NULL) if ((globals = cvec_new(0)) == NULL)
goto done; goto done;
/* load cli syntax */ /* load cli syntax */
if (cligen_parse_str(cli_cligen(h), cbuf_get(cbuf), if (cligen_parse_str(cli_cligen(h), cbuf_get(cb),
"yang2cli", ptnew, globals) < 0) "yang2cli", ptnew, globals) < 0)
goto done; goto done;
cvec_free(globals); cvec_free(globals);
@ -850,6 +875,7 @@ yang2cli(clicon_handle h,
retval = 0; retval = 0;
done: done:
cbuf_free(cbuf); if (cb)
cbuf_free(cb);
return retval; return retval;
} }

View file

@ -175,10 +175,14 @@ typedef struct yang_stmt yang_stmt; /* forward */
* @note unions not cached * @note unions not cached
*/ */
struct yang_type_cache{ struct yang_type_cache{
int yc_options; int yc_options; /* See YANG_OPTIONS_* that determines pattern/
cvec *yc_cvv; /* range and length restriction */ fraction fields. */
char *yc_pattern; cvec *yc_cvv; /* Range and length restriction. (if YANG_OPTION_
uint8_t yc_fraction; LENGTH|RANGE. Can be a vector if multiple
ranges*/
char *yc_pattern; /* regex (posix) (if YANG_OPTIONS_PATTERN) */
uint8_t yc_fraction; /* Fraction digits for decimal64 (if
YANG_OPTIONS_FRACTION_DIGITS */
yang_stmt *yc_resolved; /* Resolved type object, can be NULL - note direct ptr */ yang_stmt *yc_resolved; /* Resolved type object, can be NULL - note direct ptr */
}; };
typedef struct yang_type_cache yang_type_cache; typedef struct yang_type_cache yang_type_cache;

View file

@ -1262,6 +1262,10 @@ ys_populate_range(yang_stmt *ys,
/* This handles non-resolved also */ /* This handles non-resolved also */
if (clicon_type2cv(origtype, restype, ys, &cvtype) < 0) if (clicon_type2cv(origtype, restype, ys, &cvtype) < 0)
goto done; goto done;
if (!cv_isint(cvtype) && cvtype != CGV_DEC64){
clicon_err(OE_YANG, 0, "The range substatement only applies to int types, not to type: %s", origtype);
goto done;
}
if (range_parse(ys, cvtype, fraction_digits) < 0) if (range_parse(ys, cvtype, fraction_digits) < 0)
goto done; goto done;
retval = 0; retval = 0;

View file

@ -872,16 +872,20 @@ resolve_restrictions(yang_stmt *yrange,
* @param[in] yorig (original) type yang-stmt where original 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] ys (transitive) yang-stmt where current search is based
* @param[in] ytype yang-stmt object containing currently resolving type * @param[in] ytype yang-stmt object containing currently resolving type
* @param[out] yrestype resolved type. return built-in type or NULL. mandatory * @param[out] yrestype Resolved type. return built-in type or NULL.
* @param[out] options pointer to flags field of optional values. optional * @param[out] options Flags field of optional values, see YANG_OPTIONS_*
* @param[out] cvv pointer to cvec with min range or length. * @param[out] cvv Cvec with min/max range or length.
* If options&YANG_OPTIONS_RANGE or YANG_OPTIONS_LENGTH * Present if options&YANG_OPTIONS_RANGE|_LENGTH.
* @param[out] pattern pointer to static string of yang string pattern. optional * Can be a vector if multiple ranges
* @param[out] pattern String of POSIX regexp pattern
* Present if options&YANG_OPTIONS_PATTERN
* @param[out] fraction for decimal64, how many digits after period * @param[out] fraction for decimal64, how many digits after period
* Present if options&YANG_OPTIONS_FRACTION_DIGITS
* @retval 0 OK. Note yrestype may still be NULL. * @retval 0 OK. Note yrestype may still be NULL.
* @retval -1 Error, clicon_err handles errors * @retval -1 Error, clicon_err handles errors
* The setting of the options argument has the following semantics: * The setting of the options argument has the following semantics:
* options&YANG_OPTIONS_RANGE or YANG_OPTIONS_LENGTH --> mincv and max _can_ be set * options&YANG_OPTIONS_RANGE or YANG_OPTIONS_LENGTH --> cvv is set containing
* array of range_min, range_max cv:s
* options&YANG_OPTIONS_PATTERN --> pattern is set * options&YANG_OPTIONS_PATTERN --> pattern is set
* options&YANG_OPTIONS_FRACTION_DIGITS --> fraction is set * options&YANG_OPTIONS_FRACTION_DIGITS --> fraction is set
* Note that the static output strings (type, pattern) should be copied if used asap. * Note that the static output strings (type, pattern) should be copied if used asap.
@ -1004,16 +1008,20 @@ yang_type_resolve(yang_stmt *yorig,
* @endcode * @endcode
* @param[in] ys yang-stmt, leaf or leaf-list * @param[in] ys yang-stmt, leaf or leaf-list
* @param[out] origtype original type may be derived or built-in * @param[out] origtype original type may be derived or built-in
* @param[out] yrestype pointer to resolved type stmt. should be built-in or NULL * @param[out] yrestype Resolved type. return built-in type or NULL.
* @param[out] options pointer to flags field of optional values * @param[out] options Flags field of optional values, see YANG_OPTIONS_*
* @param[out] mincv pointer to cv of min range or length. optional * @param[out] cvv Cvec with min/max range or length.
* @param[out] maxcv pointer to cv of max range or length. optional * Present if options&YANG_OPTIONS_RANGE|_LENGTH.
* @param[out] pattern pointer to static string of yang string pattern. optional * Can be a vector if multiple ranges
* @param[out] pattern yang string pattern POSIX regexp patterns
* Present if options&YANG_OPTIONS_PATTERN
* @param[out] fraction for decimal64, how many digits after period * @param[out] fraction for decimal64, how many digits after period
* Present if options&YANG_OPTIONS_FRACTION_DIGITS
* @retval 0 OK, but note that restype==NULL means not resolved. * @retval 0 OK, but note that restype==NULL means not resolved.
* @retval -1 Error, clicon_err handles errors * @retval -1 Error, clicon_err handles errors
* The setting of the options argument has the following semantics: * The setting of the options argument has the following semantics:
* options&YANG_OPTIONS_RANGE or YANG_OPTIONS_LENGTH --> mincv and max _can_ be set * options&YANG_OPTIONS_RANGE or YANG_OPTIONS_LENGTH --> cvv is set containing
* array of range_min, range_max cv:s
* options&YANG_OPTIONS_PATTERN --> pattern is set * options&YANG_OPTIONS_PATTERN --> pattern is set
* options&YANG_OPTIONS_FRACTION_DIGITS --> fraction is set * options&YANG_OPTIONS_FRACTION_DIGITS --> fraction is set
* Note that the static output strings (type, pattern) should be copied if used asap. * Note that the static output strings (type, pattern) should be copied if used asap.

View file

@ -1,7 +1,6 @@
#!/bin/bash #!/bin/bash
# Advanced union types and generated code # Advanced union types and generated code
# and enum w values # and enum w values
# XXX NO SUPPORT FOR lists of ranges and lengths !!!
# Magic line must be first in script (see README.md) # Magic line must be first in script (see README.md)
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
@ -142,7 +141,14 @@ module example{
} }
leaf num4 { leaf num4 {
type uint8 { type uint8 {
range "1..2 | 42"; range "1..2 | 42..50";
}
}
leaf dec {
/* For test of multiple ranges with decimal64. More than 2, single range*/
type decimal64 {
fraction-digits 3;
range "-3.5..-2.5 | 0.0 | 10.0..20.0";
} }
} }
leaf len1 { leaf len1 {
@ -162,10 +168,9 @@ module example{
} }
leaf len4 { leaf len4 {
type string { type string {
range "1 .. 2 | 42"; length "2 .. 3 | 20..29";
} }
} }
typedef mybits { typedef mybits {
description "Test adding several bits"; description "Test adding several bits";
type bits { type bits {
@ -191,6 +196,7 @@ module example{
pattern '\w{4}'; pattern '\w{4}';
} }
} }
} }
EOF EOF
@ -209,10 +215,10 @@ if [ $BE -ne 0 ]; then
sleep $RCWAIT sleep $RCWAIT
fi fi
new "cli set transitive string" new "cli set transitive string. type is alpha followed by number and is defined in three levels of modules"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c talle x99" 0 "^$" expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c talle x99" 0 "^$"
new "cli set transitive string error" new "cli set transitive string error. Wrong type"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c talle 9xx" 255 "^$" expectfn "$clixon_cli -1f $cfg -l o -y $fyang set c talle 9xx" 255 "^$"
new "netconf set transitive string error" new "netconf set transitive string error"
@ -310,7 +316,7 @@ expectfn "$clixon_cli -1f $cfg -l o -y $fyang validate" 0 "^$"
new "cli range test num1 1 OK" new "cli range test num1 1 OK"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num1 1" 0 "^$" expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num1 1" 0 "^$"
#new "cli range test num1 -100 ok" # XXX - cant be given on cmd line #new "cli range test num1 -100 ok" # XXX -/minus cant be given as argv
#expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num1 \-100" 0 "^$" #expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num1 \-100" 0 "^$"
new "cli range test num1 2 error" new "cli range test num1 2 error"
@ -377,18 +383,23 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candid
new "netconf discard-changes" new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
#-------- num4 multiple ranges 1..2 | 42 #-------- num4 multiple ranges 1..2 | 42..50
new "cli range test num4 multiple 0 fail"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num4 0" 255 "^$"
new "cli range test num4 multiple 2 ok" new "cli range test num4 multiple 2 ok"
expectfn "$clixon_cli -1f $cfg -l e -y $fyang set num4 2" 0 "^$" expectfn "$clixon_cli -1f $cfg -l e -y $fyang set num4 2" 0 "^$"
new "cli range test num4 multiple 20 fail"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num4 20" 255 "^$"
new "cli range test num4 multiple 42 ok"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num4 42" 0 "^$"
new "cli range test num4 multiple 99 fail" new "cli range test num4 multiple 99 fail"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num4 99" 255 "^$" expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num4 99" 255 "^$"
# See https://github.com/clicon/clixon/issues/59
#new "cli range test num4 multiple 42 ok"
#expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num4 42" 0 "^$"
new "netconf range set num4 multiple 2" new "netconf range set num4 multiple 2"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><num4 xmlns="urn:example:clixon">42</num4></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><num4 xmlns="urn:example:clixon">42</num4></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
@ -410,6 +421,60 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candid
new "netconf discard-changes" new "netconf discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$" expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
#-------- dec64 multiple ranges -3.5..-2.5 | 0.0 | 10.0..20.0
# XXX how to enter negative numbers in bash string and cli -1?
new "cli range dec64 multiple 0 ok"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set dec 0" 0 "^$"
new "cli range dec64 multiple 0.1 fail"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num4 0.1" 255 "^$"
new "cli range dec64 multiple 15.0 ok"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set dec 15.0" 0 "^$"
new "cli range dec64 multiple 30.0 fail"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set dec 30.0" 255 "^$"
new "dec64 discard-changes"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]]>]]>" "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
# Same with netconf
new "netconf range dec64 -3.59"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><dec xmlns="urn:example:clixon">-3.59</dec></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf range dec64 -3.59 validate fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>dec</bad-element></error-info><error-severity>error</error-severity><error-message>Number out of range'
new "netconf range dec64 -3.5"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><dec xmlns="urn:example:clixon">-3.500</dec></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf range dec64 -3.5 validate ok"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
new "netconf range dec64 -2"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><dec xmlns="urn:example:clixon">-2</dec></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf range dec64 -2 validate fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>dec</bad-element></error-info><error-severity>error</error-severity><error-message>Number out of range'
new "netconf range dec64 -0.001"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><dec xmlns="urn:example:clixon">-0.001</dec></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf range dec64 -0.001 validate fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>dec</bad-element></error-info><error-severity>error</error-severity><error-message>Number out of range'
new "netconf range dec64 0.0"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><dec xmlns="urn:example:clixon">0.0</dec></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf range dec64 0.0 validate ok"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><ok/></rpc-reply>]]>]]>$'
new "netconf range dec64 +0.001"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '<rpc><edit-config><target><candidate/></target><config><dec xmlns="urn:example:clixon">+0.001</dec></config></edit-config></rpc>]]>]]>' "^<rpc-reply><ok/></rpc-reply>]]>]]>$"
new "netconf range dec64 +0.001 validate fail"
expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><validate><source><candidate/></source></validate></rpc>]]>]]>" '^<rpc-reply><rpc-error><error-type>application</error-type><error-tag>bad-element</error-tag><error-info><bad-element>dec</bad-element></error-info><error-severity>error</error-severity><error-message>Number out of range'
#----------------string ranges--------------------- #----------------string ranges---------------------
#-------- len1 single range (2) #-------- len1 single range (2)
new "cli length test len1 1 fail" new "cli length test len1 1 fail"
@ -443,19 +508,24 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "<rpc><discard-changes/></rpc>]
#-------- len3 min max range #-------- len3 min max range
new "cli range test len3 42 ok" new "cli range ptest len3 42 ok"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len3 hsakjdhkjsahdkjsahdksahdksajdhsakjhd" 0 "^$" expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len3 hsakjdhkjsahdkjsahdksahdksajdhsakjhd" 0 "^$"
#-------- len4 multiple ranges 1..2 | 42 (only first range) #-------- len4 multiple ranges 2..3 | 20-29
new "cli length test len4 3 error" new "cli length test len4 1 error"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len4 abc" 255 "^$" expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len4 a" 255 "^$"
new "cli length test len4 2 ok" new "cli length test len4 2 ok"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len4 ab" 255 "^$" expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len4 ab" 0 "^$"
# See https://github.com/clicon/clixon/issues/59 new "cli length test len4 10 error"
#new "cli length test len4 42 ok" expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len4 abcdefghij" 255 "^$"
#expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len4 hsakjdhkjsahdkjsahdksahdksajdhsakjhd" 0 "^$"
new "cli length test len4 20 ok"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len4 abcdefghijabcdefghija" 0 "^$"
new "cli length test len4 30 error"
expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len4 abcdefghijabcdefghijabcdefghij" 255 "^$"
# XSD schema -> POSIX ECE translation # XSD schema -> POSIX ECE translation
new "cli yang pattern \d ok" new "cli yang pattern \d ok"