diff --git a/.gitignore b/.gitignore index c04c1244..1d8e315b 100644 --- a/.gitignore +++ b/.gitignore @@ -44,5 +44,5 @@ build-root/*.tar.xz build-root/*.rpm build-root/rpmbuild -test/public +test/site.sh doc/html \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index d0728483..b64cdd5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -112,6 +112,7 @@ * Fix the original error in cvtype_max2str - * by adding a fraction_digits argument. - */ -static char * -cvtype_max2str_dup2(enum cv_type type, - int fraction_digits) -{ - int len; - char *str; - - if (type!=CGV_DEC64 || fraction_digits==0) - return cvtype_max2str_dup(type); - if ((len = cvtype_max2str(type, NULL, 0)) < 0) - return NULL; - if ((str = (char *)malloc(len+1)) == NULL) - return NULL; - memset(str, '\0', len+1); - len = snprintf(str, len+1, "%" PRId64 ".0", (INT64_MAX/((int)pow(10,fraction_digits)))); - return str; -} - /*! 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 * patterns, (eg regexp:"[0.9]*"). @@ -208,18 +186,17 @@ yang2cli_var_sub(clicon_handle h, char *helptext, enum cv_type cvtype, int options, - cg_var *mincv, - cg_var *maxcv, + cvec *cvv, char *pattern, uint8_t fraction_digits ) { int retval = -1; char *type; - char *r; yang_stmt *yi = NULL; int i = 0; char *cvtypestr; + cg_var *cv; if (cvtype == CGV_VOID){ retval = 0; @@ -276,44 +253,30 @@ yang2cli_var_sub(clicon_handle h, if (options & YANG_OPTIONS_FRACTION_DIGITS) cprintf(cb, " fraction-digits:%u", fraction_digits); + if (options & (YANG_OPTIONS_RANGE|YANG_OPTIONS_LENGTH)){ - assert(mincv || maxcv); - cprintf(cb, " %s[", (options&YANG_OPTIONS_RANGE)?"range":"length"); - if (mincv){ - if ((r = cv2str_dup(mincv)) == NULL){ - clicon_err(OE_UNIX, errno, "cv2str_dup"); - goto done; - } - cprintf(cb, "%s:", r); - free(r); - r = NULL; - } - if (maxcv != NULL){ - if ((r = cv2str_dup(maxcv)) == NULL){ - clicon_err(OE_UNIX, errno, "cv2str_dup"); - goto done; - } - } - else{ /* Cligen does not have 'max' keyword in range so need to find actual - max value of type if yang range expression is 0..max - */ - if (cvtype==CGV_STRING){ - if ((r = malloc(512)) == NULL){ - clicon_err(OE_UNIX, errno, "malloc"); - goto done; - } - snprintf(r, 512, "%d", MAXPATHLEN); - } - else { - if ((r = cvtype_max2str_dup2(cvtype, fraction_digits)) == NULL){ - clicon_err(OE_UNIX, errno, "cvtype_max2str"); - goto done; + /* Loop through range_min and range_min..rang_max */ + i = 0; + while (iys_argument); + cv = cvec_i(cvv, i++); + if (strcmp(cv_name_get(cv),"range_min") == 0){ + cprintf(cb, " %s[", (options&YANG_OPTIONS_RANGE)?"range":"length"); + cv2cbuf(cv, cb); + cprintf(cb,":"); + /* probe next */ + if (iys_argument:NULL; @@ -370,7 +332,7 @@ yang2cli_var_union_one(clicon_handle h, if (clicon_type2cv(origtype, restype, &cvtype) < 0) goto done; if ((retval = yang2cli_var_sub(h, ys, ytype, cb, helptext, cvtype, - options, mincv, maxcv, pattern, fraction_digits)) < 0) + options, cvv, pattern, fraction_digits)) < 0) goto done; } retval = 0; @@ -438,8 +400,7 @@ yang2cli_var(clicon_handle h, char *origtype; yang_stmt *yrestype; /* resolved type */ char *restype; /* resolved type */ - cg_var *mincv = NULL; - cg_var *maxcv = NULL; + cvec *cvv = NULL; char *pattern = NULL; uint8_t fraction_digits = 0; enum cv_type cvtype; @@ -448,7 +409,7 @@ yang2cli_var(clicon_handle h, char *type; if (yang_type_get(ys, &origtype, &yrestype, - &options, &mincv, &maxcv, &pattern, &fraction_digits) < 0) + &options, &cvv, &pattern, &fraction_digits) < 0) goto done; restype = yrestype?yrestype->ys_argument:NULL; @@ -485,7 +446,7 @@ yang2cli_var(clicon_handle h, if (completionp) cprintf(cb, "("); if ((retval = yang2cli_var_sub(h, ys, yrestype, cb, helptext, cvtype, - options, mincv, maxcv, pattern, fraction_digits)) < 0) + options, cvv, pattern, fraction_digits)) < 0) goto done; if (completionp){ if (cli_expand_var_generate(h, ys, cvtype, cb, diff --git a/lib/clixon/clixon_string.h b/lib/clixon/clixon_string.h index 1b2b20fc..5895401d 100644 --- a/lib/clixon/clixon_string.h +++ b/lib/clixon/clixon_string.h @@ -87,6 +87,7 @@ int uri_percent_decode(char *enc, char **str); const char *clicon_int2str(const map_str2int *mstab, int i); int clicon_str2int(const map_str2int *mstab, char *str); int nodeid_split(char *nodeid, char **prefix, char **id); +char *clixon_trim(char *str); #ifndef HAVE_STRNDUP char *clicon_strndup (const char *, size_t); #endif /* ! HAVE_STRNDUP */ diff --git a/lib/clixon/clixon_yang.h b/lib/clixon/clixon_yang.h index b0635385..3842b225 100644 --- a/lib/clixon/clixon_yang.h +++ b/lib/clixon/clixon_yang.h @@ -176,8 +176,7 @@ typedef struct yang_stmt yang_stmt; /* forward */ */ struct yang_type_cache{ int yc_options; - cg_var *yc_mincv; - cg_var *yc_maxcv; + cvec *yc_cvv; /* range and length restriction */ char *yc_pattern; uint8_t yc_fraction; yang_stmt *yc_resolved; /* Resolved type object, can be NULL - note direct ptr */ diff --git a/lib/clixon/clixon_yang_type.h b/lib/clixon/clixon_yang_type.h index 8fecdd5f..bbdfe79e 100644 --- a/lib/clixon/clixon_yang_type.h +++ b/lib/clixon/clixon_yang_type.h @@ -55,11 +55,11 @@ * Prototypes */ int yang_type_cache_set(yang_type_cache **ycache, - yang_stmt *resolved, int options, cg_var *mincv, - cg_var *maxcv, char *pattern, uint8_t fraction); -int yang_type_cache_get(yang_type_cache *ycache, - yang_stmt **resolved, int *options, cg_var **mincv, - cg_var **maxcv, char **pattern, uint8_t *fraction); + yang_stmt *resolved, int options, + cvec *cvv, char *pattern, uint8_t fraction); +int yang_type_cache_get(yang_type_cache *ycache, yang_stmt **resolved, + int *options, cvec **cvv, char **pattern, + uint8_t *fraction); int yang_type_cache_cp(yang_type_cache **ycnew, yang_type_cache *ycold); int yang_type_cache_free(yang_type_cache *ycache); int ys_resolve_type(yang_stmt *ys, void *arg); @@ -69,12 +69,11 @@ yang_stmt *yang_find_identity(yang_stmt *ys, char *identity); int ys_cv_validate(cg_var *cv, yang_stmt *ys, char **reason); int clicon_type2cv(char *type, char *rtype, enum cv_type *cvtype); int yang_type_get(yang_stmt *ys, char **otype, yang_stmt **restype, - int *options, cg_var **mincv, cg_var **maxcv, char **pattern, + int *options, cvec **cvv, char **pattern, uint8_t *fraction_digits); -int yang_type_resolve(yang_stmt *ys, yang_stmt *ytype, - yang_stmt **restype, int *options, - cg_var **mincv, cg_var **maxcv, - char **pattern, uint8_t *fraction); +int yang_type_resolve(yang_stmt *ys, yang_stmt *ytype, + yang_stmt **restype, int *options, + cvec **cvv, char **pattern, uint8_t *fraction); #endif /* _CLIXON_YANG_TYPE_H_ */ diff --git a/lib/src/clixon_string.c b/lib/src/clixon_string.c index b3e5e588..733a1ca4 100644 --- a/lib/src/clixon_string.c +++ b/lib/src/clixon_string.c @@ -57,14 +57,15 @@ /*! Split string into a vector based on character delimiters. Using malloc * * The given string is split into a vector where the delimiter can be - * any of the characters in the specified delimiter string. + * _any_ of the characters in the specified delimiter string. * * The vector returned is one single memory block that must be freed * by the caller * * @code - * char **vec = NULL; - * int nvec; + * char **vec = NULL; + * char *v; + * int nvec; * if ((vec = clicon_strsep("/home/user/src/clixon", "/", &nvec)) == NULL) * err; * for (i=0; i [[a,"b"][c="d"] * kalle&c=d -> [[c="d"]] # Discard elements with no delim2 * XXX differentiate between error and null cvec. @@ -610,6 +614,26 @@ nodeid_split(char *nodeid, return retval; } +/*! Trim blanks from front and end of a string, return new string + * @param[in] str + * @retval s Pointer into existing str after trimming blanks + */ +char * +clixon_trim(char *str) +{ + char *s = str; + int i; + + while (strlen(s) && isblank(s[0])) + s++; + for (i=0; iys_argument, "enumeration")) goto done; diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index 7a81bc6b..66590a56 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -1068,7 +1068,7 @@ 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, 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 */ @@ -1133,12 +1133,62 @@ ys_populate_list(yang_stmt *ys, return 0; } -/*! Populate range and length statements +/*! Set range or length boundary for built-in yang types + * Help functions to range and length statements + */ +static int +bound_add(yang_stmt *ys, + enum cv_type cvtype, + char *name, + char *val, + int options, + uint8_t fraction_digits + ) +{ + int retval = -1; + cg_var *cv; + char *reason = NULL; + int ret = 1; + + if ((cv = cvec_add(ys->ys_cvec, cvtype)) == NULL){ + clicon_err(OE_YANG, errno, "cvec_add"); + goto done; + } + if (cv_name_set(cv, name) == NULL){ + clicon_err(OE_YANG, errno, "cv_name_set(%s)", name); + goto done; + } + if (options & YANG_OPTIONS_FRACTION_DIGITS && cvtype == CGV_DEC64) + cv_dec64_n_set(cv, fraction_digits); + if (strcmp(val, "min") == 0) + cv_min_set(cv); + else if (strcmp(val, "max") == 0) + cv_max_set(cv); + else if ((ret = cv_parse1(val, cv, &reason)) < 0){ + clicon_err(OE_YANG, errno, "cv_parse1"); + goto done; + } + if (ret == 0){ /* parsing failed */ + clicon_err(OE_YANG, errno, "range statement %s: %s", val, reason); + free(reason); + goto done; + } + retval = 0; + done: + return retval; +} + +/*! Populate string built-in range statement * * Create cvec variables "range_min" and "range_max". Assume parent is type. - * Actually: min..max [| min..max]* - * where min,max is integer or keywords 'min' or 'max. - * We only allow one range, ie not 1..2|4..5 + * Actually: bound[..bound] (| bound[..bound])* + * where bound is integer, decimal or keywords 'min' or 'max. + * RFC 7950 9.2.4: + * A range consists of an explicit value, or a lower-inclusive bound, + * two consecutive dots "..", and an upper-inclusive bound. Multiple + * values or ranges can be given, separated by "|". If multiple values + * or ranges are given, they all MUST be disjoint and MUST be in + * ascending order */ static int ys_populate_range(yang_stmt *ys, @@ -1152,11 +1202,11 @@ ys_populate_range(yang_stmt *ys, int options = 0x0; uint8_t fraction_digits; enum cv_type cvtype = CGV_ERR; - char *minstr = NULL; - char *maxstr; - cg_var *cv; - char *reason = NULL; - int cvret; + char **vec = NULL; + char *v; + char *v2; + int nvec; + int i; yparent = ys->ys_parent; /* Find parent: type */ if (yparent->yn_keyword != Y_TYPE){ @@ -1164,81 +1214,90 @@ ys_populate_range(yang_stmt *ys, goto done; } if (yang_type_resolve(ys, (yang_stmt*)yparent, &yrestype, - &options, NULL, NULL, NULL, &fraction_digits) < 0) + &options, NULL, NULL, &fraction_digits) < 0) goto done; restype = yrestype?yrestype->ys_argument:NULL; origtype = yarg_id((yang_stmt*)yparent); /* This handles non-resolved also */ if (clicon_type2cv(origtype, restype, &cvtype) < 0) goto done; - /* special case for strings, where limit is length, not a string */ - if (cvtype == CGV_STRING) - cvtype = CGV_UINT64; - if ((minstr = strdup(ys->ys_argument)) == NULL){ - clicon_err(OE_YANG, errno, "strdup"); + if ((vec = clicon_strsep(ys->ys_argument, "|", &nvec)) == NULL) goto done; - } - if ((maxstr = strstr(minstr, "..")) != NULL){ - if (strlen(maxstr) < 2){ - clicon_err(OE_YANG, 0, "range statement: %s not on the form: ..", - ys->ys_argument); - goto done; - } - minstr[maxstr-minstr] = '\0'; - maxstr += 2; - /* minstr and maxstr need trimming */ - if (isblank(minstr[strlen(minstr)-1])) - minstr[strlen(minstr)-1] = '\0'; - if (isblank(maxstr[0])) - maxstr++; - if ((cv = cvec_add(ys->ys_cvec, cvtype)) == NULL){ - clicon_err(OE_YANG, errno, "cvec_add"); - goto done; + for (i=0; iys_cvec, cvtype)) == NULL){ - clicon_err(OE_YANG, errno, "cvec_add"); - goto done; - } - if (cv_name_set(cv, "range_max") == NULL){ - clicon_err(OE_YANG, errno, "cv_name_set"); - goto done; - } - if (options & YANG_OPTIONS_FRACTION_DIGITS && cvtype == CGV_DEC64) - cv_dec64_n_set(cv, fraction_digits); - if ((cvret = cv_parse1(maxstr, cv, &reason)) < 0){ - clicon_err(OE_YANG, errno, "cv_parse1"); - goto done; - } - if (cvret == 0){ /* parsing failed */ - clicon_err(OE_YANG, errno, "range statement, max: %s", reason); - free(reason); - goto done; - } + if (v2) + if (bound_add(ys, cvtype, "range_max",v2, + options, fraction_digits) < 0) + goto done; } retval = 0; done: - if (minstr) - free(minstr); + if (vec) + free(vec); + return retval; +} + +/*! Populate integer built-in length statement + * + * Create cvec variables "range_min" and "range_max". Assume parent is type. + * Actually: len[..len] (| len[..len])* + * len is unsigned integer or keywords 'min' or 'max. + * RFC 7950 9.4.4 + * A length range consists of an explicit value, or a lower bound, two + * consecutive dots "..", and an upper bound. Multiple values or ranges + * can be given, separated by "|". Length-restricting values MUST NOT + * be negative. If multiple values or ranges are given, they all MUST + * be disjoint and MUST be in ascending order. + */ +static int +ys_populate_length(yang_stmt *ys, + void *arg) +{ + int retval = -1; + yang_node *yparent; /* type */ + enum cv_type cvtype = CGV_ERR; + char **vec = NULL; + char *v; + int nvec; + int i; + char *v2; + + yparent = ys->ys_parent; /* Find parent: type */ + if (yparent->yn_keyword != Y_TYPE){ + clicon_err(OE_YANG, 0, "parent should be type"); + goto done; + } + cvtype = CGV_UINT64; + if ((vec = clicon_strsep(ys->ys_argument, "|", &nvec)) == NULL) + goto done; + for (i=0; iyc_resolved = resolved; ycache->yc_options = options; - if (mincv && (ycache->yc_mincv = cv_dup(mincv)) == NULL){ - clicon_err(OE_UNIX, errno, "cv_dup"); - goto done; - } - if (maxcv && (ycache->yc_maxcv = cv_dup(maxcv)) == NULL){ - clicon_err(OE_UNIX, errno, "cv_dup"); - goto done; + if (cvv){ + if ((ycache->yc_cvv = cvec_dup(cvv)) == NULL){ + clicon_err(OE_UNIX, errno, "cvec_dup"); + goto done; + } } if (pattern && (ycache->yc_pattern = strdup(pattern)) == NULL){ clicon_err(OE_UNIX, errno, "strdup"); @@ -155,8 +152,7 @@ int yang_type_cache_get(yang_type_cache *ycache, yang_stmt **resolved, int *options, - cg_var **mincv, - cg_var **maxcv, + cvec **cvv, char **pattern, uint8_t *fraction) { @@ -164,10 +160,8 @@ yang_type_cache_get(yang_type_cache *ycache, *resolved = ycache->yc_resolved; if (options) *options = ycache->yc_options; - if (mincv) - *mincv = ycache->yc_mincv; - if (maxcv) - *maxcv = ycache->yc_maxcv; + if (cvv) + *cvv = ycache->yc_cvv; if (pattern) *pattern = ycache->yc_pattern; if (fraction) @@ -181,14 +175,13 @@ yang_type_cache_cp(yang_type_cache **ycnew, { int retval = -1; int options; - cg_var *mincv; - cg_var *maxcv; + cvec *cvv; char *pattern; uint8_t fraction; yang_stmt *resolved; - yang_type_cache_get(ycold, &resolved, &options, &mincv, &maxcv, &pattern, &fraction); - if (yang_type_cache_set(ycnew, resolved, options, mincv, maxcv, pattern, fraction) < 0) + yang_type_cache_get(ycold, &resolved, &options, &cvv, &pattern, &fraction); + if (yang_type_cache_set(ycnew, resolved, options, cvv, pattern, fraction) < 0) goto done; retval = 0; done: @@ -198,10 +191,8 @@ yang_type_cache_cp(yang_type_cache **ycnew, int yang_type_cache_free(yang_type_cache *ycache) { - if (ycache->yc_mincv) - cv_free(ycache->yc_mincv); - if (ycache->yc_maxcv) - cv_free(ycache->yc_maxcv); + if (ycache->yc_cvv) + cvec_free(ycache->yc_cvv); if (ycache->yc_pattern) free(ycache->yc_pattern); free(ycache); @@ -220,8 +211,7 @@ ys_resolve_type(yang_stmt *ys, { int retval = -1; int options = 0x0; - cg_var *mincv = NULL; - cg_var *maxcv = NULL; + cvec *cvv = NULL; char *pattern = NULL; uint8_t fraction = 0; yang_stmt *resolved = NULL; @@ -231,12 +221,12 @@ ys_resolve_type(yang_stmt *ys, * Note that the resolved type could be ys itself. */ if (yang_type_resolve((yang_stmt*)ys->ys_parent, ys, &resolved, - &options, &mincv, &maxcv, &pattern, &fraction) < 0) + &options, &cvv, &pattern, &fraction) < 0) goto done; /* Cache the resolve locally */ if (yang_type_cache_set(&ys->ys_typecache, - resolved, options, mincv, maxcv, pattern, fraction) < 0) + resolved, options, cvv, pattern, fraction) < 0) goto done; retval = 0; done: @@ -388,132 +378,121 @@ static int cv_validate1(cg_var *cv, enum cv_type cvtype, int options, - cg_var *range_min, - cg_var *range_max, + cvec *cvv, char *pattern, yang_stmt *yrestype, char *restype, char **reason) { int retval = 1; /* OK */ + cg_var *cv1; + cg_var *cv2; int retval2; yang_stmt *yi = NULL; - unsigned int u = 0; - int i = 0; char *str; int found; char **vec = NULL; int nvec; char *v; + uint64_t uu = 0; + int64_t ii = 0; + int i; + int ret; if (reason && *reason){ free(*reason); *reason = NULL; } + /* check options first for length and range */ + if ((options & YANG_OPTIONS_RANGE) != 0 || + (options & YANG_OPTIONS_LENGTH) != 0){ + i = 0; + while (iys_argument:NULL; @@ -664,7 +623,7 @@ ys_cv_validate_union_one(yang_stmt *ys, } if (retval == 0) goto done; - if ((retval = cv_validate1(cvt, cvtype, options, range_min, range_max, + if ((retval = cv_validate1(cvt, cvtype, options, cvv, pattern, yrt, restype, reason)) < 0) goto done; } @@ -736,8 +695,7 @@ ys_cv_validate(cg_var *cv, int retval = -1; cg_var *ycv; /* cv of yang-statement */ int options = 0; - cg_var *range_min = NULL; - cg_var *range_max = NULL; + cvec *cvv = NULL; char *pattern = NULL; enum cv_type cvtype; char *type; /* orig type */ @@ -756,8 +714,7 @@ ys_cv_validate(cg_var *cv, } ycv = ys->ys_cv; if (yang_type_get(ys, &type, &yrestype, - &options, &range_min, &range_max, &pattern, - &fraction) < 0) + &options, &cvv, &pattern, &fraction) < 0) goto done; restype = yrestype?yrestype->ys_argument:NULL; if (clicon_type2cv(type, restype, &cvtype) < 0) @@ -782,7 +739,7 @@ ys_cv_validate(cg_var *cv, retval = retval2; /* invalid (0) with latest reason or valid 1 */ } else - if ((retval = cv_validate1(cv, cvtype, options, range_min, range_max, pattern, + if ((retval = cv_validate1(cv, cvtype, options, cvv, pattern, yrestype, restype, reason)) < 0) goto done; done: @@ -889,7 +846,17 @@ yang_find_identity(yang_stmt *ys, return yid; } -/* +/*! Resolve type restrictions, return contraining parameters + * @param[in] yrange Yang type range restriction if any + * @param[in] ylength Yang type length restriction if any + * @param[in] ypattern Yang type pattern restriction if any + * @param[in] yfraction Yang type fraction restriction if any + * @param[out] options Pointer to flags field of optional values. optional + * @param[out] cvv Pointer to cvec with min range or length. + * If options&YANG_OPTIONS_RANGE or YANG_OPTIONS_LENGTH + * @param[out] pattern Pointer to static string of yang string pattern. optional + * @param[out] fraction For decimal64, how many digits after period + * @retval 0 OK. */ static int resolve_restrictions(yang_stmt *yrange, @@ -897,19 +864,16 @@ resolve_restrictions(yang_stmt *yrange, yang_stmt *ypattern, yang_stmt *yfraction, int *options, - cg_var **mincv, - cg_var **maxcv, + cvec **cvv, char **pattern, uint8_t *fraction) { - if (options && mincv && maxcv && yrange != NULL){ - *mincv = cvec_find(yrange->ys_cvec, "range_min"); - *maxcv = cvec_find(yrange->ys_cvec, "range_max"); + if (options && cvv && yrange != NULL){ + *cvv = yrange->ys_cvec; *options |= YANG_OPTIONS_RANGE; } - if (options && mincv && maxcv && ylength != NULL){ - *mincv = cvec_find(ylength->ys_cvec, "range_min"); /* XXX fel typ */ - *maxcv = cvec_find(ylength->ys_cvec, "range_max"); + if (options && cvv && ylength != NULL){ + *cvv = ylength->ys_cvec; *options |= YANG_OPTIONS_LENGTH; } if (options && pattern && ypattern != NULL){ @@ -928,8 +892,8 @@ resolve_restrictions(yang_stmt *yrange, * @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 - * @param[out] mincv pointer to cv with min range or length. If options&YANG_OPTIONS_RANGE - * @param[out] maxcv pointer to cv with max range or length. If options&YANG_OPTIONS_RANGE + * @param[out] cvv pointer to cvec with min range or length. + * If options&YANG_OPTIONS_RANGE or YANG_OPTIONS_LENGTH * @param[out] pattern pointer to static string of yang string pattern. optional * @param[out] fraction for decimal64, how many digits after period * @retval 0 OK. Note yrestype may still be NULL. @@ -946,8 +910,7 @@ yang_type_resolve(yang_stmt *ys, yang_stmt *ytype, yang_stmt **yrestype, int *options, - cg_var **mincv, - cg_var **maxcv, + cvec **cvv, char **pattern, uint8_t *fraction) { @@ -970,8 +933,8 @@ yang_type_resolve(yang_stmt *ys, prefix = yarg_prefix(ytype); /* And this its prefix */ /* Cache does not work for eg string length 32? */ if (!yang_builtin(type) && ytype->ys_typecache != NULL){ - if (yang_type_cache_get(ytype->ys_typecache, - yrestype, options, mincv, maxcv, pattern, fraction) < 0) + if (yang_type_cache_get(ytype->ys_typecache, yrestype, + options, cvv, pattern, fraction) < 0) goto done; goto ok; } @@ -984,7 +947,7 @@ yang_type_resolve(yang_stmt *ys, if (prefix == NULL && yang_builtin(type)){ *yrestype = ytype; resolve_restrictions(yrange, ylength, ypattern, yfraction, options, - mincv, maxcv, pattern, fraction); + cvv, pattern, fraction); goto ok; } @@ -1022,13 +985,12 @@ yang_type_resolve(yang_stmt *ys, } /* recursively resolve this new type */ if (yang_type_resolve(ys, rytype, yrestype, - options, mincv, maxcv, pattern, fraction) < 0) + options, cvv, pattern, fraction) < 0) goto done; /* overwrites the resolved if any */ - resolve_restrictions(yrange, ylength, ypattern, yfraction, - options, mincv, maxcv, pattern, fraction); + resolve_restrictions(yrange, ylength, ypattern, yfraction, options, + cvv, pattern, fraction); } - ok: retval = 0; done: @@ -1042,11 +1004,11 @@ yang_type_resolve(yang_stmt *ys, * @code * yang_stmt *yrestype; * int options; - * int64_t min, max; + * cvec *cvv = NULL; * char *pattern; * uint8_t fraction; * - * if (yang_type_get(ys, &type, &yrestype, &options, &min, &max, &pattern, &fraction) < 0) + * if (yang_type_get(ys, &type, &yrestype, &options, &cvv, &pattern, &fraction) < 0) * goto err; * if (yrestype == NULL) # unresolved * goto err; @@ -1078,8 +1040,7 @@ yang_type_get(yang_stmt *ys, char **origtype, yang_stmt **yrestype, int *options, - cg_var **mincv, - cg_var **maxcv, + cvec **cvv, char **pattern, uint8_t *fraction ) @@ -1100,7 +1061,7 @@ yang_type_get(yang_stmt *ys, if (origtype) *origtype = type; if (yang_type_resolve(ys, ytype, yrestype, - options, mincv, maxcv, pattern, fraction) < 0) + options, cvv, pattern, fraction) < 0) goto done; clicon_debug(3, "%s: %s %s->%s", __FUNCTION__, ys->ys_argument, type, *yrestype?(*yrestype)->ys_argument:"null"); diff --git a/test/README.md b/test/README.md index 59832663..1326365e 100644 --- a/test/README.md +++ b/test/README.md @@ -2,8 +2,9 @@ This directory contains testing code for clixon and the example application. Assumes setup of http daemon as describe under apps/restonf -- clixon A top-level script clones clixon in /tmp and starts all.sh. You can copy this file (review it first) and place as cron script +- Jenkinsfile Makefile for Jenkins tests. Build clixon and run tests. - all.sh Run through all tests named 'test*.sh' in this directory. Therefore, if you place a test in this directory matching 'test*.sh' it will be run automatically. By default the script will exit on first error. Run as `all.sh summary` to continue and print a summary on all tests. +- site.sh Add your site-specific modifications here - test_nacm.sh Auth tests using internal NACM - test_nacm_ext.sh Auth tests using external NACM (separate file) - test_cli.sh CLI tests @@ -12,6 +13,7 @@ application. Assumes setup of http daemon as describe under apps/restonf - test_yang.sh Yang tests for constructs not in the example. - test_leafref.sh Yang leafref tests - test_datastore.sh Datastore tests +- and many more... Example runs: ``` diff --git a/test/test_openconfig.sh b/test/test_openconfig.sh index 47574fa2..f5f56bcf 100755 --- a/test/test_openconfig.sh +++ b/test/test_openconfig.sh @@ -3,9 +3,6 @@ # Note that the openconfig test suites are patched to counter CLixon issues as follows: # - release/models/mpls/openconfig-mpls-te.yang # issue: https://github.com/clicon/clixon/issues/60 -# - release/models/wifi/types/openconfig-wifi-types.yang -# issue: https://github.com/clicon/clixon/issues/59 -# # Yang specifics: multi-keys and empty type APPNAME=example diff --git a/test/test_type.sh b/test/test_type.sh index 20f6f7aa..188107a6 100755 --- a/test/test_type.sh +++ b/test/test_type.sh @@ -1,8 +1,10 @@ #!/bin/bash # Advanced union types and generated code # and enum w values +# XXX NO SUPPORT FOR lists of ranges and lengths !!! APPNAME=example # include err() and new() functions and creates $dir + . ./lib.sh cfg=$dir/conf_yang.xml @@ -123,57 +125,47 @@ module example{ enum down; } } - leaf length1 { - type string { - length "1"; - } - } -/* leaf length2 { - type string { - length "max"; - } - } - leaf length3 { - type string { - length "min"; - } - }*/ - leaf length4 { - type string { - length "4..4000"; - } - } -/* leaf length5 { - type string { - length "min..max"; - } - }*/ leaf num1 { type int32 { range "1"; } } -/* leaf num2 { - type int32 { - range "min"; - } - } - leaf num3 { - type int32 { - range "max"; - } - } -*/ - leaf num4 { + leaf num2 { type int32 { range "4..4000"; } } -/* leaf num5 { - type int32 { + leaf num3 { + type uint8 { range "min..max"; } - }*/ + } + leaf num4 { /* XXX multiple ranges not supported yet - only first*/ + type uint8 { + range "1 .. 2 | 42"; + } + } + leaf len1 { + type string { + length "2"; + } + } + leaf len2 { + type string { + length "4..4000"; + } + } + leaf len3 { + type string { + length "min..max"; + } + } + leaf len4 { + type string { + range "1 .. 2 | 42"; + } + } + typedef mybits { description "Test adding several bits"; type bits { @@ -303,6 +295,70 @@ expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 '-1]]>]]>' "^]]>]]>$" + +new "netconf validate num1 -1 wrong" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" '^applicationbad-elementnum1errorNumber out of range: -1]]>]]>$' + +new "cli range test num2 1000 ok" +expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num2 1000" 0 "^$" + +new "cli range test num2 3 error" +expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num2 3" 255 "^$" + +new "cli range test num2 5000 error" +expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num2 5000" 255 "^$" + +new "cli range test num3 42 ok" +expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num3 42" 0 "^$" + +new "cli range test num3 260 error" +expectfn "$clixon_cli -1f $cfg -l o -y $fyang set num3 260" 255 "^$" + +#----------------string ranges--------------------- + +new "cli length test len1 1 error" +expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len1 x" 255 "^$" + +new "cli length test len1 2 OK" +expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len1 xy" 0 "^$" + +new "cli length test len1 3 error" +expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len1 hej" 255 "^$" + +new "netconf discard-changes" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^]]>]]>$" + +new "netconf length set len1 1" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 'x]]>]]>' "^]]>]]>$" + +new "netconf validate len1 1 wrong" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" '^applicationbad-elementlen1errorstring length out of range: 1]]>]]>$' + +new "cli length test len2 42 ok" +expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len2 hejhophdsakjhkjsadhkjsahdkjsad" 0 "^$" + +new "netconf discard-changes" +expecteof "$clixon_netconf -qf $cfg -y $fyang" 0 "]]>]]>" "^]]>]]>$" + +new "cli length test len2 3 error" +expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len2 ab" 255 "^$" + +new "cli range test len3 42 ok" +expectfn "$clixon_cli -1f $cfg -l o -y $fyang set len3 hsakjdhkjsahdkjsahdksahdksajdhsakjhd" 0 "^$" + if [ $BE -eq 0 ]; then exit # BE fi