* Partially corrected: [yang type range statement does not support multiple values](https://github.com/clicon/clixon/issues/59).
* Should work for netconf and restconf, but not for CLI. * Fixed again: [Range parsing is not RFC 7950 compliant](https://github.com/clicon/clixon/issues/71)
This commit is contained in:
parent
f718c716b6
commit
19343c2b21
6 changed files with 329 additions and 202 deletions
|
|
@ -624,13 +624,14 @@ clixon_trim(char *str)
|
|||
char *s = str;
|
||||
int i;
|
||||
|
||||
while (strlen(s) && isblank(s[0]))
|
||||
while (strlen(s) && isblank(s[0])) /* trim from front */
|
||||
s++;
|
||||
for (i=0; i<strlen(s); i++)
|
||||
if (isblank(s[i])){
|
||||
for (i=strlen(s)-1; i>=0; i--){ /* trim from rear */
|
||||
if (isblank(s[i]))
|
||||
s[i] = '\0';
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1152,9 +1152,7 @@ bound_add(yang_stmt *ys,
|
|||
enum cv_type cvtype,
|
||||
char *name,
|
||||
char *val,
|
||||
int options,
|
||||
uint8_t fraction_digits
|
||||
)
|
||||
uint8_t fraction_digits)
|
||||
{
|
||||
int retval = -1;
|
||||
cg_var *cv;
|
||||
|
|
@ -1169,7 +1167,7 @@ bound_add(yang_stmt *ys,
|
|||
clicon_err(OE_YANG, errno, "cv_name_set(%s)", name);
|
||||
goto done;
|
||||
}
|
||||
if (options & YANG_OPTIONS_FRACTION_DIGITS && cvtype == CGV_DEC64)
|
||||
if (cvtype == CGV_DEC64)
|
||||
cv_dec64_n_set(cv, fraction_digits);
|
||||
if (strcmp(val, "min") == 0)
|
||||
cv_min_set(cv);
|
||||
|
|
@ -1189,6 +1187,43 @@ bound_add(yang_stmt *ys,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Common range length parsing of "x .. y | z..w " statements
|
||||
*/
|
||||
static int
|
||||
range_parse(yang_stmt *ys,
|
||||
enum cv_type cvtype,
|
||||
uint8_t fraction_digits)
|
||||
{
|
||||
int retval = -1;
|
||||
char **vec = NULL;
|
||||
int nvec;
|
||||
int i;
|
||||
char *v;
|
||||
char *v2;
|
||||
|
||||
if ((vec = clicon_strsep(ys->ys_argument, "|", &nvec)) == NULL)
|
||||
goto done;
|
||||
for (i=0; i<nvec; i++){
|
||||
v = vec[i];
|
||||
if ((v2 = strstr(v, "..")) != NULL){
|
||||
*v2 = '\0';
|
||||
v2 += 2;
|
||||
v2 = clixon_trim(v2); /* trim blanks */
|
||||
}
|
||||
v = clixon_trim(v); /* trim blanks */
|
||||
if (bound_add(ys, cvtype, "range_min", v, fraction_digits) < 0)
|
||||
goto done;
|
||||
if (v2)
|
||||
if (bound_add(ys, cvtype, "range_max", v2, fraction_digits) < 0)
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (vec)
|
||||
free(vec);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Populate string built-in range statement
|
||||
*
|
||||
* Create cvec variables "range_min" and "range_max". Assume parent is type.
|
||||
|
|
@ -1213,11 +1248,6 @@ ys_populate_range(yang_stmt *ys,
|
|||
int options = 0x0;
|
||||
uint8_t fraction_digits;
|
||||
enum cv_type cvtype = CGV_ERR;
|
||||
char **vec = NULL;
|
||||
char *v;
|
||||
char *v2;
|
||||
int nvec;
|
||||
int i;
|
||||
|
||||
yparent = ys->ys_parent; /* Find parent: type */
|
||||
if (yparent->yn_keyword != Y_TYPE){
|
||||
|
|
@ -1232,28 +1262,10 @@ ys_populate_range(yang_stmt *ys,
|
|||
/* This handles non-resolved also */
|
||||
if (clicon_type2cv(origtype, restype, ys, &cvtype) < 0)
|
||||
goto done;
|
||||
if ((vec = clicon_strsep(ys->ys_argument, "|", &nvec)) == NULL)
|
||||
if (range_parse(ys, cvtype, fraction_digits) < 0)
|
||||
goto done;
|
||||
for (i=0; i<nvec; i++){
|
||||
v = vec[i++];
|
||||
v = clixon_trim(v); /* trim blanks */
|
||||
if ((v2 = strstr(v, "..")) != NULL){
|
||||
*v2 = '\0';
|
||||
v2 += 2;
|
||||
v2 = clixon_trim(v2); /* trim blanks */
|
||||
}
|
||||
if (bound_add(ys, cvtype, "range_min", v,
|
||||
options, fraction_digits) < 0)
|
||||
goto done;
|
||||
if (v2)
|
||||
if (bound_add(ys, cvtype, "range_max",v2,
|
||||
options, fraction_digits) < 0)
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (vec)
|
||||
free(vec);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -1276,11 +1288,6 @@ ys_populate_length(yang_stmt *ys,
|
|||
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){
|
||||
|
|
@ -1288,27 +1295,10 @@ ys_populate_length(yang_stmt *ys,
|
|||
goto done;
|
||||
}
|
||||
cvtype = CGV_UINT64;
|
||||
if ((vec = clicon_strsep(ys->ys_argument, "|", &nvec)) == NULL)
|
||||
if (range_parse(ys, cvtype, 0) < 0)
|
||||
goto done;
|
||||
for (i=0; i<nvec; i++){
|
||||
|
||||
v = vec[i++];
|
||||
v = clixon_trim(v); /* trim blanks */
|
||||
if ((v2 = strstr(v, "..")) != NULL){
|
||||
*v2 = '\0';
|
||||
v2 += 2;
|
||||
v2 = clixon_trim(v2); /* trim blanks */
|
||||
}
|
||||
if (bound_add(ys, cvtype, "range_min", v, 0, 0) < 0)
|
||||
goto done;
|
||||
if (v2)
|
||||
if (bound_add(ys, cvtype, "range_max",v2, 0, 0) < 0)
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (vec)
|
||||
free(vec);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -373,7 +373,9 @@ cv_validate1(cg_var *cv,
|
|||
uint64_t uu = 0;
|
||||
int64_t ii = 0;
|
||||
int i;
|
||||
int ret;
|
||||
int reti; /* must keep signed, unsigned and string retval */
|
||||
int retu; /* separated due to different error handling */
|
||||
int rets;
|
||||
|
||||
if (reason && *reason){
|
||||
free(*reason);
|
||||
|
|
@ -384,89 +386,86 @@ cv_validate1(cg_var *cv,
|
|||
(options & YANG_OPTIONS_LENGTH) != 0){
|
||||
i = 0;
|
||||
while (i<cvec_len(cvv)){
|
||||
cv1 = cvec_i(cvv, i++);
|
||||
if (strcmp(cv_name_get(cv1),"range_min") == 0){
|
||||
if (i<cvec_len(cvv) &&
|
||||
(cv2 = cvec_i(cvv, i)) != NULL &&
|
||||
strcmp(cv_name_get(cv2),"range_max") == 0){
|
||||
i++;
|
||||
}
|
||||
else
|
||||
cv2 = cv1;
|
||||
ret = 0;
|
||||
switch (cvtype){
|
||||
case CGV_INT8:
|
||||
ii = cv_int8_get(cv);
|
||||
ret = range_check(ii, cv1, cv2, int8);
|
||||
break;
|
||||
case CGV_INT16:
|
||||
ii = cv_int16_get(cv);
|
||||
ret = range_check(ii, cv1, cv2, int16);
|
||||
break;
|
||||
case CGV_INT32:
|
||||
ii = cv_int32_get(cv);
|
||||
ret = range_check(ii, cv1, cv2, int32);
|
||||
break;
|
||||
case CGV_DEC64: /* XXX look at fraction-digit? */
|
||||
case CGV_INT64:
|
||||
ii = cv_int64_get(cv);
|
||||
ret = range_check(ii, cv1, cv2, int64);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (ret){
|
||||
if (reason)
|
||||
*reason = cligen_reason("Number out of range: %" PRId64, ii);
|
||||
goto fail;
|
||||
break;
|
||||
}
|
||||
ret = 0;
|
||||
switch (cvtype){
|
||||
case CGV_UINT8:
|
||||
uu = cv_uint8_get(cv);
|
||||
ret = range_check(uu, cv1, cv2, uint8);
|
||||
break;
|
||||
case CGV_UINT16:
|
||||
uu = cv_uint16_get(cv);
|
||||
ret = range_check(uu, cv1, cv2, uint16);
|
||||
break;
|
||||
case CGV_UINT32:
|
||||
uu = cv_uint32_get(cv);
|
||||
ret = range_check(uu, cv1, cv2, uint32);
|
||||
break;
|
||||
case CGV_UINT64:
|
||||
uu = cv_uint32_get(cv);
|
||||
ret = range_check(uu, cv1, cv2, uint64);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (ret){
|
||||
if (reason)
|
||||
*reason = cligen_reason("Number out of range: %" PRIu64, uu);
|
||||
goto fail;
|
||||
break;
|
||||
}
|
||||
ret = 0;
|
||||
switch (cvtype){
|
||||
case CGV_STRING:
|
||||
case CGV_REST:
|
||||
if ((str = cv_string_get(cv)) == NULL)
|
||||
break;
|
||||
uu = strlen(str);
|
||||
if (range_check(uu, cv1, cv2, uint64)){
|
||||
if (reason)
|
||||
*reason = cligen_reason("string length out of range: %" PRIu64, uu);
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
cv1 = cvec_i(cvv, i++); /* Increment to check for max pair */
|
||||
if (strcmp(cv_name_get(cv1),"range_min") != 0){
|
||||
clicon_err(OE_YANG, EINVAL, "Internal error, expected range_min");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if (i<cvec_len(cvv) &&
|
||||
(cv2 = cvec_i(cvv, i)) != NULL &&
|
||||
strcmp(cv_name_get(cv2),"range_max") == 0){
|
||||
i++;
|
||||
}
|
||||
else
|
||||
cv2 = cv1;
|
||||
reti = 0; retu = 0; rets = 0;
|
||||
switch (cvtype){
|
||||
case CGV_INT8:
|
||||
ii = cv_int8_get(cv);
|
||||
reti = range_check(ii, cv1, cv2, int8);
|
||||
break;
|
||||
case CGV_INT16:
|
||||
ii = cv_int16_get(cv);
|
||||
reti = range_check(ii, cv1, cv2, int16);
|
||||
break;
|
||||
case CGV_INT32:
|
||||
ii = cv_int32_get(cv);
|
||||
reti = range_check(ii, cv1, cv2, int32);
|
||||
break;
|
||||
case CGV_DEC64: /* XXX look at fraction-digit? */
|
||||
case CGV_INT64:
|
||||
ii = cv_int64_get(cv);
|
||||
reti = range_check(ii, cv1, cv2, int64);
|
||||
break;
|
||||
case CGV_UINT8:
|
||||
uu = cv_uint8_get(cv);
|
||||
retu = range_check(uu, cv1, cv2, uint8);
|
||||
break;
|
||||
case CGV_UINT16:
|
||||
uu = cv_uint16_get(cv);
|
||||
retu = range_check(uu, cv1, cv2, uint16);
|
||||
break;
|
||||
case CGV_UINT32:
|
||||
uu = cv_uint32_get(cv);
|
||||
retu = range_check(uu, cv1, cv2, uint32);
|
||||
break;
|
||||
case CGV_UINT64:
|
||||
uu = cv_uint32_get(cv);
|
||||
retu = range_check(uu, cv1, cv2, uint64);
|
||||
break;
|
||||
case CGV_STRING:
|
||||
case CGV_REST:
|
||||
if ((str = cv_string_get(cv)) == NULL)
|
||||
break;
|
||||
uu = strlen(str);
|
||||
rets = range_check(uu, cv1, cv2, uint64);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* Error handling for signed and unsigned, strings in switch
|
||||
* OK: if check OK
|
||||
* Failure: check fails and it is the last
|
||||
*/
|
||||
if ((reti==0 && retu==0 && rets == 0))
|
||||
goto step1ok;
|
||||
/* Check fails */
|
||||
if (i==cvec_len(cvv)){ /* And it is last */
|
||||
if (reason){
|
||||
if (reti)
|
||||
*reason = cligen_reason("Number out of range: %"
|
||||
PRId64, ii);
|
||||
else if (retu)
|
||||
*reason = cligen_reason("Number out of range: %"
|
||||
PRIu64, uu);
|
||||
else
|
||||
*reason = cligen_reason("string length out of range: %" PRIu64, uu);
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
} /* while i<cvec_len(cvv) */
|
||||
}
|
||||
step1ok:
|
||||
/* then check options for others */
|
||||
switch (cvtype){
|
||||
case CGV_STRING:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue