This commit is contained in:
Olof hagsand 2019-04-14 14:43:20 +02:00
commit 71da2ac6cb
30 changed files with 809 additions and 1103 deletions

View file

@ -0,0 +1,48 @@
/*
*
***** BEGIN LICENSE BLOCK *****
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
This file is part of CLIXON.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Alternatively, the contents of this file may be used under the terms of
the GNU General Public License Version 3 or later (the "GPL"),
in which case the provisions of the GPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of the GPL, and not to allow others to
use your version of this file under the terms of Apache License version 2,
indicate your decision by deleting the provisions above and replace them with
the notice and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the Apache License version 2 or the GPL.
***** END LICENSE BLOCK *****
* First effort in customizing error output strings.
* Here just very simple constants that can be edited and recompiled by
* an integrator.
*/
#ifndef _CLIXON_ERR_STRING_H_
#define _CLIXON_ERR_STRING_H_
/* If internal netconf validation operation failed in the backend */
#define CLIXON_ERRSTR_VALIDATE_FAILED "Validate failed. Edit and try again or discard changes"
/* If internal netconf commit operation failed in the backend */
#define CLIXON_ERRSTR_COMMIT_FAILED "Commit failed. Edit and try again or discard changes"
#endif /* _CLIXON_ERR_STRING_H_ */

View file

@ -68,7 +68,7 @@ int xml_spec_populate_rpc(clicon_handle h, cxobj *x, yang_stmt *yspec);
int xml_spec_populate(cxobj *x, void *arg);
int api_path2xpath(yang_stmt *yspec, cvec *cvv, int offset, cbuf *xpath);
int api_path2xml(char *api_path, yang_stmt *yspec, cxobj *xtop,
yang_class nodeclass, cxobj **xpathp, yang_stmt **ypathp);
yang_class nodeclass, int strict, cxobj **xpathp, yang_stmt **ypathp);
int xml_merge(cxobj *x0, cxobj *x1, yang_stmt *yspec, char **reason);
int yang_enum_int_value(cxobj *node, int32_t *val);

View file

@ -169,7 +169,7 @@ typedef enum yang_class yang_class;
#define yang_schemanode(y) (yang_datanode(y) || (y)->ys_keyword == Y_RPC || (y)->ys_keyword == Y_CHOICE || (y)->ys_keyword == Y_CASE || (y)->ys_keyword == Y_INPUT || (y)->ys_keyword == Y_OUTPUT || (y)->ys_keyword == Y_NOTIFICATION)
typedef struct yang_stmt yang_stmt; /* forward */
typedef struct yang_stmt yang_stmt; /* Defined in clixon_yang_internal */
/*! Yang type cache. Yang type statements can cache all typedef info here
* @note unions not cached
@ -189,6 +189,7 @@ typedef struct yang_type_cache yang_type_cache;
/*! yang statement
*/
struct yang_stmt{
int ys_len; /* Number of children */
struct yang_stmt **ys_stmt; /* Vector of children statement pointers */
@ -197,7 +198,6 @@ struct yang_stmt{
char *ys_argument; /* String / argument depending on keyword */
int ys_flags; /* Flags according to YANG_FLAG_* above */
/*--------------here common for all -------*/
yang_stmt *ys_module; /* Shortcut to "my" module. Augmented
nodes can belong to other
modules than the ancestor module */
@ -218,31 +218,22 @@ struct yang_stmt{
Y_TYPE & identity: store all derived types
*/
yang_type_cache *ys_typecache; /* If ys_keyword==Y_TYPE, cache all typedef data except unions */
int _ys_vector_i; /* internal use: yn_each */
};
#if 0 /* Backward compatible */
typedef struct yang_stmt yang_node;
typedef struct yang_stmt yang_spec;
#define yn_len ys_len
#define yn_stmt ys_stmt
#define yn_parent ys_parent
#define yn_keyword ys_keyword
#define yn_argument ys_argument
#define yn_flags ys_flags
#define yp_len ys_len
#define yp_stmt ys_stmt
#define yp_parent ys_parent
#define yp_keyword ys_keyword
#define yp_argument ys_argument
#define yp_flags ys_flags
#endif
typedef int (yang_applyfn_t)(yang_stmt *ys, void *arg);
/*
* Prototypes
*/
/* Access functions */
yang_stmt *yang_parent_get(yang_stmt *ys);
enum rfc_6020 yang_keyword_get(yang_stmt *ys);
char *yang_argument_get(yang_stmt *ys);
cg_var *yang_cv_get(yang_stmt *ys);
cvec *yang_cvec_get(yang_stmt *ys);
/* Other functions */
yang_stmt *yspec_new(void);
yang_stmt *ys_new(enum rfc_6020 keyw);
int ys_free(yang_stmt *ys);

View file

@ -124,9 +124,12 @@ clean:
lex.clixon_xml_parse.c : clixon_xml_parse.l clixon_xml_parse.tab.h
$(LEX) -Pclixon_xml_parse clixon_xml_parse.l # -d is debug
clixon_xml_parse.tab.c clixon_xml_parse.tab.h: clixon_xml_parse.y
clixon_xml_parse.tab.h: clixon_xml_parse.y
$(YACC) -l -d -b clixon_xml_parse -p clixon_xml_parse clixon_xml_parse.y # -t is debug
# extra rule to avoid parallell yaccs
clixon_xml_parse.tab.c: clixon_xml_parse.tab.h
lex.clixon_xml_parse.o : lex.clixon_xml_parse.c clixon_xml_parse.tab.h # special rule to for make clean to work
$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -Wno-error -c $<
@ -134,9 +137,12 @@ lex.clixon_xml_parse.o : lex.clixon_xml_parse.c clixon_xml_parse.tab.h # special
lex.clixon_yang_parse.c : clixon_yang_parse.l clixon_yang_parse.tab.h
$(LEX) -Pclixon_yang_parse clixon_yang_parse.l # -d is debug
clixon_yang_parse.tab.c clixon_yang_parse.tab.h: clixon_yang_parse.y
clixon_yang_parse.tab.h: clixon_yang_parse.y
$(YACC) -l -d -b clixon_yang_parse -p clixon_yang_parse clixon_yang_parse.y # -t is debug
# extra rule to avoid parallell yaccs
clixon_yang_parse.tab.c: clixon_yang_parse.tab.h
lex.clixon_yang_parse.o : lex.clixon_yang_parse.c clixon_yang_parse.tab.h
$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -Wno-error -c $<
@ -144,9 +150,12 @@ lex.clixon_yang_parse.o : lex.clixon_yang_parse.c clixon_yang_parse.tab.h
lex.clixon_json_parse.c : clixon_json_parse.l clixon_json_parse.tab.h
$(LEX) -Pclixon_json_parse clixon_json_parse.l # -d is debug
clixon_json_parse.tab.c clixon_json_parse.tab.h: clixon_json_parse.y
clixon_json_parse.tab.h: clixon_json_parse.y
$(YACC) -l -d -b clixon_json_parse -p clixon_json_parse clixon_json_parse.y # -t is debug
# extra rule to avoid parallell yaccs
clixon_json_parse.tab.c: clixon_json_parse.tab.h
lex.clixon_json_parse.o : lex.clixon_json_parse.c clixon_json_parse.tab.h
$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -Wno-error -c $<
@ -154,9 +163,12 @@ lex.clixon_json_parse.o : lex.clixon_json_parse.c clixon_json_parse.tab.h
lex.clixon_xpath_parse.c : clixon_xpath_parse.l clixon_xpath_parse.tab.h
$(LEX) -Pclixon_xpath_parse clixon_xpath_parse.l # -d is debug
clixon_xpath_parse.tab.c clixon_xpath_parse.tab.h: clixon_xpath_parse.y
clixon_xpath_parse.tab.h: clixon_xpath_parse.y
$(YACC) -l -d -b clixon_xpath_parse -p clixon_xpath_parse clixon_xpath_parse.y # -t is debug
# extra rule to avoid parallell yaccs
clixon_xpath_parse.tab.c: clixon_xpath_parse.tab.h
lex.clixon_xpath_parse.o : lex.clixon_xpath_parse.c clixon_xpath_parse.tab.h
$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -Wno-error -c $<

View file

@ -708,9 +708,9 @@ xmldb_get(clicon_handle h,
* @note if xvec is given, then purge tree, if not return whole tree.
* @see xmldb_get This version uses direct cache access and needs to be
* cleanued up after use
* @see xmldb_get1_clean Must call after use
* @see xmldb_get1_clear Must call after use
* @note If !CLICON_XMLDB_CACHE you need to free xret after use
* This should probably replace xmldb_get completely
* @note If CLICON_XMLDB_CACHE mark|change flags set, need to clear after call
*/
int
xmldb_get1(clicon_handle h,

View file

@ -173,23 +173,27 @@ clixon_plugin_find(clicon_handle h,
* @param[in] file Which plugin to load
* @param[in] function Which function symbol to load and call
* @param[in] dlflags See man(3) dlopen
* @retval cp Clixon plugin structure
* @retval NULL Error
* @param[out] cpp Clixon plugin structure (if retval is 1)
* @retval 1 OK
* @retval 0 Failed load, log, skip and continue with other plugins
* @retval -1 Error
* @see clixon_plugins_load Load all plugins
*/
static clixon_plugin *
static int
plugin_load_one(clicon_handle h,
char *file,
char *function,
int dlflags)
int dlflags,
clixon_plugin **cpp)
{
char *error;
void *handle = NULL;
plginit2_t *initfn;
int retval = -1;
char *error;
void *handle = NULL;
plginit2_t *initfn;
clixon_plugin_api *api = NULL;
clixon_plugin *cp = NULL;
char *name;
char *p;
clixon_plugin *cp = NULL;
char *name;
char *p;
clicon_debug(1, "%s file:%s function:%s", __FUNCTION__, file, function);
dlerror(); /* Clear any existing error */
@ -201,7 +205,7 @@ plugin_load_one(clicon_handle h,
/* call plugin_init() if defined, eg CLIXON_PLUGIN_INIT or CLIXON_BACKEND_INIT */
if ((initfn = dlsym(handle, function)) == NULL){
clicon_err(OE_PLUGIN, errno, "Failed to find %s when loading clixon plugin %s", CLIXON_PLUGIN_INIT, file);
goto err;
goto done;
}
if ((error = (char*)dlerror()) != NULL) {
clicon_err(OE_UNIX, 0, "dlsym: %s: %s", file, error);
@ -211,11 +215,12 @@ plugin_load_one(clicon_handle h,
if ((api = initfn(h)) == NULL) {
if (!clicon_errno){ /* if clicon_err() is not called then log and continue */
clicon_log(LOG_DEBUG, "Warning: failed to initiate %s", strrchr(file,'/')?strchr(file, '/'):file);
dlclose(handle);
retval = 0;
goto done;
}
else{
clicon_err(OE_PLUGIN, errno, "Failed to initiate %s", strrchr(file,'/')?strchr(file, '/'):file);
goto err;
goto done;
}
}
/* Note: sizeof clixon_plugin_api which is largest of clixon_plugin_api:s */
@ -235,15 +240,19 @@ plugin_load_one(clicon_handle h,
snprintf(cp->cp_name, sizeof(cp->cp_name), "%*s",
(int)strlen(name), name);
if (api)
cp->cp_api = *api;
cp->cp_api = *api;
clicon_debug(1, "%s", __FUNCTION__);
if (cp){
*cpp = cp;
cp = NULL;
}
retval = 1;
done:
return cp;
err:
if (handle)
if (retval != 1 && handle)
dlclose(handle);
return NULL;
if (cp)
free(cp);
return retval;
}
/*! Load a set of plugin objects from a directory and and call their init-function
@ -266,6 +275,7 @@ clixon_plugins_load(clicon_handle h,
int i;
char filename[MAXPATHLEN];
clixon_plugin *cp;
int ret;
clicon_debug(1, "%s", __FUNCTION__);
/* Get plugin objects names from plugin directory */
@ -276,8 +286,10 @@ clixon_plugins_load(clicon_handle h,
snprintf(filename, MAXPATHLEN-1, "%s/%s", dir, dp[i].d_name);
clicon_debug(1, "DEBUG: Loading plugin '%.*s' ...",
(int)strlen(filename), filename);
if ((cp = plugin_load_one(h, filename, function, RTLD_NOW)) == NULL)
if ((ret = plugin_load_one(h, filename, function, RTLD_NOW, &cp)) < 0)
goto done;
if (ret == 0)
continue;
_clixon_nplugins++;
if ((_clixon_plugins = realloc(_clixon_plugins, _clixon_nplugins*sizeof(clixon_plugin))) == NULL) {
clicon_err(OE_UNIX, errno, "realloc");

View file

@ -70,6 +70,7 @@
#include "clixon_xpath.h"
#include "clixon_proto.h"
#include "clixon_err.h"
#include "clixon_err_string.h"
#include "clixon_proto_client.h"
/*! Send internal netconf rpc from client to backend
@ -689,7 +690,7 @@ clicon_rpc_validate(clicon_handle h,
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error("Validate failed. Edit and try again or discard changes", xerr);
clicon_rpc_generate_error(CLIXON_ERRSTR_VALIDATE_FAILED, xerr);
goto done;
}
retval = 0;
@ -721,7 +722,7 @@ clicon_rpc_commit(clicon_handle h)
if (clicon_rpc_msg(h, msg, &xret, NULL) < 0)
goto done;
if ((xerr = xpath_first(xret, "//rpc-error")) != NULL){
clicon_rpc_generate_error("Commit failed. Edit and try again or discard changes", xerr);
clicon_rpc_generate_error(CLIXON_ERRSTR_COMMIT_FAILED, xerr);
goto done;
}
retval = 0;

View file

@ -626,6 +626,7 @@ xml_child_i_set(cxobj *xt,
* ...
* }
* @endcode
* @note makes uses _x_vector_i:can be changed if list changed between calls
*/
cxobj *
xml_child_each(cxobj *xparent,
@ -817,7 +818,7 @@ xml_cv_set(cxobj *x,
*
* @retval xmlobj if found.
* @retval NULL if no such node found.
* @see xml_find_type wich is a more generic function
* @see xml_find_type A more generic function
*/
cxobj *
xml_find(cxobj *x_up,

View file

@ -663,6 +663,7 @@ xml_yang_validate_add(cxobj *xt,
char *body;
int ret;
cxobj *x;
enum cv_type cvtype;
/* if not given by argument (overide) use default link
and !Node has a config sub-statement and it is false */
@ -688,17 +689,28 @@ xml_yang_validate_add(cxobj *xt,
/* In the union case, value is parsed as generic REST type,
* needs to be reparsed when concrete type is selected
*/
if ((body = xml_body(xt)) != NULL){
if ((body = xml_body(xt)) == NULL){
/* We do not allow ints to be empty. Otherwise NULL strings
* are considered as "" */
cvtype = cv_type_get(cv);
if (cv_isint(cvtype) || cvtype == CGV_BOOL || cvtype == CGV_DEC64){
if (netconf_bad_element(cbret, "application", yt->ys_argument, "Invalid NULL value") < 0)
goto done;
goto fail;
}
}
else{
if (cv_parse1(body, cv, &reason) != 1){
if (netconf_bad_element(cbret, "application", yt->ys_argument, reason) < 0)
goto done;
goto fail;
}
if ((ys_cv_validate(cv, yt, &reason)) != 1){
if (netconf_bad_element(cbret, "application", yt->ys_argument, reason) < 0)
goto done;
goto fail;
}
}
if ((ys_cv_validate(cv, yt, &reason)) != 1){
if (netconf_bad_element(cbret, "application", yt->ys_argument, reason) < 0)
goto done;
goto fail;
}
break;
default:
@ -1987,6 +1999,7 @@ api_path2xml_vec(char **vec,
cxobj *x0,
yang_stmt *y0,
yang_class nodeclass,
int strict,
cxobj **xpathp,
yang_stmt **ypathp)
{
@ -2069,9 +2082,10 @@ api_path2xml_vec(char **vec,
valvec = NULL;
}
if (restval==NULL){
// XXX patch to allow for lists without restval to be backward compat
// clicon_err(OE_XML, 0, "malformed key, expected '=restval'");
// goto done;
if (strict){
clicon_err(OE_XML, 0, "malformed key, expected '=restval'");
goto fail;
}
}
else{
if ((valvec = clicon_strsep(restval, ",", &nvalvec)) == NULL)
@ -2102,9 +2116,11 @@ api_path2xml_vec(char **vec,
}
break;
default: /* eg Y_CONTAINER, Y_LEAF */
if ((x = xml_new(name, x0, y)) == NULL)
goto done;
xml_type_set(x, CX_ELMNT);
if ((x = xml_find_type(x0, NULL, name, CX_ELMNT)) == NULL){ /* eg key of list */
if ((x = xml_new(name, x0, y)) == NULL)
goto done;
xml_type_set(x, CX_ELMNT);
}
break;
}
if (x && namespace){
@ -2113,7 +2129,7 @@ api_path2xml_vec(char **vec,
}
if ((retval = api_path2xml_vec(vec+1, nvec-1,
x, y,
nodeclass,
nodeclass, strict,
xpathp, ypathp)) < 1)
goto done;
ok:
@ -2160,6 +2176,7 @@ api_path2xml(char *api_path,
yang_stmt *yspec,
cxobj *xtop,
yang_class nodeclass,
int strict,
cxobj **xbotp,
yang_stmt **ybotp)
{
@ -2185,7 +2202,7 @@ api_path2xml(char *api_path,
}
nvec--; /* NULL-terminated */
if ((retval = api_path2xml_vec(vec+1, nvec,
xtop, yspec, nodeclass,
xtop, yspec, nodeclass, strict,
xbotp, ybotp)) < 1)
goto done;
xml_yang_root(*xbotp, &xroot);

View file

@ -652,9 +652,14 @@ xml_insert(cxobj *xp,
/* Ensure the intermediate state that xp is parent of x but has not yet been
* added as a child
*/
// assert(xml_parent(xi) == NULL);
// assert(y = xml_spec(xi));
if (xml_parent(xi) != NULL){
clicon_err(OE_XML, 0, "XML node %s should not have parent", xml_name(xi));
goto done;
}
if ((y = xml_spec(xi)) == NULL){
clicon_err(OE_XML, 0, "No spec found %s", xml_name(xi));
goto done;
}
upper = xml_child_nr(xp);
/* Assume if there are any attributes, they are first in the list, mask
them by raising low to skip them */

View file

@ -87,9 +87,9 @@
#include "clixon_plugin.h"
#include "clixon_data.h"
#include "clixon_options.h"
#include "clixon_yang_type.h"
#include "clixon_yang_parse.h"
#include "clixon_yang_cardinality.h"
#include "clixon_yang_type.h"
/* Size of json read buffer when reading from file*/
#define BUFLEN 1024
@ -174,6 +174,56 @@ static const map_str2int ykmap[] = {
{NULL, -1}
};
/* Access functions
*/
/*! Get yang statement parent
* @param[in] ys Yang statement node
*/
yang_stmt *
yang_parent_get(yang_stmt *ys)
{
return ys->ys_parent;
}
/*! Get yang statement keyword
* @param[in] ys Yang statement node
*/
enum rfc_6020
yang_keyword_get(yang_stmt *ys)
{
return ys->ys_keyword;
}
/*! Get yang statement context-dependent argument
* @param[in] ys Yang statement node
*/
char*
yang_argument_get(yang_stmt *ys)
{
return ys->ys_argument;
}
/*! Get yang statement CLIgen variable
* @param[in] ys Yang statement node
*/
cg_var*
yang_cv_get(yang_stmt *ys)
{
return ys->ys_cv;
}
/*! Get yang statement CLIgen variable vector
* @param[in] ys Yang statement node
*/
cvec*
yang_cvec_get(yang_stmt *ys)
{
return ys->ys_cvec;
}
/* End access functions */
/*! Create new yang specification
* @retval yspec Free with yspec_free()
* @retval NULL Error
@ -392,29 +442,38 @@ yn_insert(yang_stmt *ys_parent,
/*! Iterate through all yang statements from a yang node
*
* Note that this is not optimized, one could use 'i' as index?
* @param[in] yparent yang statement whose children should be iterated
* @param[in] yprev previous child, or NULL on init
* @code
* yang_stmt *ys = NULL;
* while ((ys = yn_each(yn, ys)) != NULL) {
* ...ys...
* yang_stmt *yprev = NULL;
* while ((yprev = yn_each(yparent, yprev)) != NULL) {
* ...yprev...
* }
* @endcode
* @note makes uses _ys_vector_i:can be changed if list changed between calls
*/
yang_stmt *
yn_each(yang_stmt *yn,
yang_stmt *ys)
yn_each(yang_stmt *yparent,
yang_stmt *yprev)
{
int i;
yang_stmt *yc = NULL;
int i;
for (i=0; i<yn->ys_len; i++){
yc = yn->ys_stmt[i];
if (ys==NULL)
return yc;
if (ys==yc)
ys = NULL;
if (yparent == NULL)
return NULL;
for (i=yprev?yprev->_ys_vector_i+1:0; i<yparent->ys_len; i++){
if ((yc = yparent->ys_stmt[i]) == NULL){
assert(yc); /* XXX Check if happens */
continue;
}
/* make room for other conditionals */
break; /* this is next object after previous */
}
return NULL;
if (i < yparent->ys_len) /* found */
yc->_ys_vector_i = i;
else
yc = NULL;
return yc;
}
/*! Find first child yang_stmt with matching keyword and argument

View file

@ -0,0 +1,91 @@
/*
*
***** BEGIN LICENSE BLOCK *****
Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
This file is part of CLIXON.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Alternatively, the contents of this file may be used under the terms of
the GNU General Public License Version 3 or later (the "GPL"),
in which case the provisions of the GPL are applicable instead
of those above. If you wish to allow use of your version of this file only
under the terms of the GPL, and not to allow others to
use your version of this file under the terms of Apache License version 2,
indicate your decision by deleting the provisions above and replace them with
the notice and other provisions required by the GPL. If you do not delete
the provisions above, a recipient may use your version of this file under
the terms of any one of the Apache License version 2 or the GPL.
***** END LICENSE BLOCK *****
* Yang functions
* @see https://tools.ietf.org/html/rfc6020 YANG 1.0
* @see https://tools.ietf.org/html/rfc7950 YANG 1.1
*/
#ifndef _CLIXON_YANG_INTERNAL_H_
#define _CLIXON_YANG_INTERNAL_H_
/*! Yang type cache. Yang type statements can cache all typedef info here
* @note unions not cached
*/
struct yang_type_cache{
int yc_options; /* See YANG_OPTIONS_* that determines pattern/
fraction fields. */
cvec *yc_cvv; /* Range and length restriction. (if YANG_OPTION_
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 */
};
typedef struct yang_type_cache yang_type_cache;
/*! yang statement
*/
struct yang_stmt{
int ys_len; /* Number of children */
struct yang_stmt **ys_stmt; /* Vector of children statement pointers */
struct yang_stmt *ys_parent; /* Backpointer to parent: yang-stmt or yang-spec */
enum rfc_6020 ys_keyword; /* See clicon_yang_parse.tab.h */
char *ys_argument; /* String / argument depending on keyword */
int ys_flags; /* Flags according to YANG_FLAG_* above */
yang_stmt *ys_module; /* Shortcut to "my" module. Augmented
nodes can belong to other
modules than the ancestor module */
char *ys_extra; /* For unknown */
cg_var *ys_cv; /* cligen variable. See ys_populate()
Following stmts have cv:s:
leaf: for default value
leaf-list,
config: boolean true or false
mandatory: boolean true or false
fraction-digits for fraction-digits
unknown-stmt (argument)
*/
cvec *ys_cvec; /* List of stmt-specific variables
Y_RANGE: range_min, range_max
Y_LIST: vector of keys
Y_TYPE & identity: store all derived types
*/
yang_type_cache *ys_typecache; /* If ys_keyword==Y_TYPE, cache all typedef data except unions */
int _ys_vector_i; /* internal use: yn_each */
};
#endif /* _CLIXON_YANG_INTERNAL_H_ */

View file

@ -364,7 +364,7 @@ cv_validate1(cg_var *cv,
cg_var *cv2;
int retval2;
yang_stmt *yi = NULL;
char *str;
char *str = NULL;
int found;
char **vec = NULL;
int nvec;
@ -435,8 +435,9 @@ cv_validate1(cg_var *cv,
case CGV_STRING:
case CGV_REST:
if ((str = cv_string_get(cv)) == NULL)
break;
uu = strlen(str);
uu = 0; /* equal no string with empty string for range check */
else
uu = strlen(str);
rets = range_check(uu, cv1, cv2, uint64);
break;
default:
@ -470,29 +471,34 @@ cv_validate1(cg_var *cv,
case CGV_STRING:
case CGV_REST:
str = cv_string_get(cv);
/* Note, if there is no value, eg <s/>, str is NULL.
*/
if (restype){
if (strcmp(restype, "enumeration") == 0){
found = 0;
yi = NULL;
while ((yi = yn_each(yrestype, yi)) != NULL){
if (yi->ys_keyword != Y_ENUM)
continue;
if (strcmp(yi->ys_argument, str) == 0){
found++;
break;
if (str != NULL)
while ((yi = yn_each(yrestype, yi)) != NULL){
if (yi->ys_keyword != Y_ENUM)
continue;
if (strcmp(yi->ys_argument, str) == 0){
found++;
break;
}
}
}
if (!found){
if (reason)
*reason = cligen_reason("'%s' does not match enumeration", str);
goto fail;
}
}
if (strcmp(restype, "bits") == 0){
if (strcmp(restype, "bits") == 0 && str != NULL){
/* The lexical representation of the bits type is a space-separated list
* of the names of the bits that are set. A zero-length string thus
* represents a value where no bits are set.
*/
nvec = 0;
if ((vec = clicon_strsep(str, " \t", &nvec)) == NULL)
goto done;
for (i=0; i<nvec; i++){
@ -521,7 +527,7 @@ cv_validate1(cg_var *cv,
char *posix = NULL;
if (regexp_xsd2posix(pattern, &posix) < 0)
goto done;
if ((retval2 = match_regexp(str, posix)) < 0){
if ((retval2 = match_regexp(str?str:"", posix)) < 0){
clicon_err(OE_DB, 0, "match_regexp: %s", pattern);
return -1;
}
@ -536,8 +542,9 @@ cv_validate1(cg_var *cv,
}
}
break;
case CGV_ERR:
case CGV_VOID:
break; /* empty type OK */
case CGV_ERR:
retval = 0;
if (reason)
*reason = cligen_reason("Invalid cv");