Dedicated xml,json,yang and xsl parser utility programs added
Sanity check of stdarg (...) added Cleanup of error messages.
This commit is contained in:
parent
1306174071
commit
85c4782e36
56 changed files with 1004 additions and 379 deletions
|
|
@ -45,11 +45,14 @@
|
|||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#define __USE_GNU /* strverscmp */
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <regex.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <syslog.h>
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
|
|
@ -74,6 +77,8 @@
|
|||
#include "clixon_yang_type.h"
|
||||
#include "clixon_yang_parse.h"
|
||||
|
||||
/* Size of json read buffer when reading from file*/
|
||||
#define BUFLEN 1024
|
||||
|
||||
/* Mapping between yang keyword string <--> clicon constants */
|
||||
static const map_str2int ykmap[] = {
|
||||
|
|
@ -158,7 +163,7 @@ yspec_new(void)
|
|||
yang_spec *yspec;
|
||||
|
||||
if ((yspec = malloc(sizeof(*yspec))) == NULL){
|
||||
clicon_err(OE_YANG, errno, "%s: malloc", __FUNCTION__);
|
||||
clicon_err(OE_YANG, errno, "malloc");
|
||||
return NULL;
|
||||
}
|
||||
memset(yspec, 0, sizeof(*yspec));
|
||||
|
|
@ -176,7 +181,7 @@ ys_new(enum rfc_6020 keyw)
|
|||
yang_stmt *ys;
|
||||
|
||||
if ((ys = malloc(sizeof(*ys))) == NULL){
|
||||
clicon_err(OE_YANG, errno, "%s: malloc", __FUNCTION__);
|
||||
clicon_err(OE_YANG, errno, "malloc");
|
||||
return NULL;
|
||||
}
|
||||
memset(ys, 0, sizeof(*ys));
|
||||
|
|
@ -184,7 +189,7 @@ ys_new(enum rfc_6020 keyw)
|
|||
/* The cvec contains stmt-specific variables. Only few stmts need variables so the
|
||||
cvec could be lazily created to save some heap and cycles. */
|
||||
if ((ys->ys_cvec = cvec_new(0)) == NULL){
|
||||
clicon_err(OE_YANG, errno, "%s: cvec_new", __FUNCTION__);
|
||||
clicon_err(OE_YANG, errno, "cvec_new");
|
||||
return NULL;
|
||||
}
|
||||
return ys;
|
||||
|
|
@ -247,7 +252,7 @@ yn_realloc(yang_node *yn)
|
|||
yn->yn_len++;
|
||||
|
||||
if ((yn->yn_stmt = realloc(yn->yn_stmt, (yn->yn_len)*sizeof(yang_stmt *))) == 0){
|
||||
clicon_err(OE_YANG, errno, "%s: realloc", __FUNCTION__);
|
||||
clicon_err(OE_YANG, errno, "realloc");
|
||||
return -1;
|
||||
}
|
||||
yn->yn_stmt[yn->yn_len - 1] = NULL; /* init field */
|
||||
|
|
@ -276,22 +281,22 @@ ys_cp(yang_stmt *ynew,
|
|||
ynew->ys_parent = NULL;
|
||||
if (yold->ys_stmt)
|
||||
if ((ynew->ys_stmt = calloc(yold->ys_len, sizeof(yang_stmt *))) == NULL){
|
||||
clicon_err(OE_YANG, errno, "%s: calloc", __FUNCTION__);
|
||||
clicon_err(OE_YANG, errno, "calloc");
|
||||
goto done;
|
||||
}
|
||||
if (yold->ys_argument)
|
||||
if ((ynew->ys_argument = strdup(yold->ys_argument)) == NULL){
|
||||
clicon_err(OE_YANG, errno, "%s: strdup", __FUNCTION__);
|
||||
clicon_err(OE_YANG, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
if (yold->ys_cv)
|
||||
if ((ynew->ys_cv = cv_dup(yold->ys_cv)) == NULL){
|
||||
clicon_err(OE_YANG, errno, "%s: cv_dup", __FUNCTION__);
|
||||
clicon_err(OE_YANG, errno, "cv_dup");
|
||||
goto done;
|
||||
}
|
||||
if (yold->ys_cvec)
|
||||
if ((ynew->ys_cvec = cvec_dup(yold->ys_cvec)) == NULL){
|
||||
clicon_err(OE_YANG, errno, "%s: cvec_dup", __FUNCTION__);
|
||||
clicon_err(OE_YANG, errno, "cvec_dup");
|
||||
goto done;
|
||||
}
|
||||
if (yold->ys_typecache){
|
||||
|
|
@ -902,7 +907,7 @@ yang_print(FILE *f,
|
|||
cbuf *cb = NULL;
|
||||
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_YANG, errno, "%s: cbuf_new", __FUNCTION__);
|
||||
clicon_err(OE_YANG, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if (yang_print_cbuf(cb, yn, 0) < 0)
|
||||
|
|
@ -998,14 +1003,14 @@ ys_populate_leaf(yang_stmt *ys,
|
|||
goto done;
|
||||
/* 2. Create the CV using cvtype and name it */
|
||||
if ((cv = cv_new(cvtype)) == NULL){
|
||||
clicon_err(OE_YANG, errno, "%s: cv_new", __FUNCTION__);
|
||||
clicon_err(OE_YANG, errno, "cv_new");
|
||||
goto done;
|
||||
}
|
||||
if (options & YANG_OPTIONS_FRACTION_DIGITS && cvtype == CGV_DEC64) /* XXX: Seems misplaced? / too specific */
|
||||
cv_dec64_n_set(cv, fraction_digits);
|
||||
|
||||
if (cv_name_set(cv, ys->ys_argument) == NULL){
|
||||
clicon_err(OE_YANG, errno, "%s: cv_new_set", __FUNCTION__);
|
||||
clicon_err(OE_YANG, errno, "cv_new_set");
|
||||
goto done;
|
||||
}
|
||||
/* 3. Check if default value. Here we parse the string in the default-stmt
|
||||
|
|
@ -1083,7 +1088,7 @@ ys_populate_range(yang_stmt *ys,
|
|||
|
||||
yparent = ys->ys_parent; /* Find parent: type */
|
||||
if (yparent->yn_keyword != Y_TYPE){
|
||||
clicon_err(OE_YANG, 0, "%s: parent should be type", __FUNCTION__);
|
||||
clicon_err(OE_YANG, 0, "parent should be type");
|
||||
goto done;
|
||||
}
|
||||
if (yang_type_resolve(ys, (yang_stmt*)yparent, &yrestype,
|
||||
|
|
@ -1103,7 +1108,8 @@ ys_populate_range(yang_stmt *ys,
|
|||
}
|
||||
if ((maxstr = strstr(minstr, "..")) != NULL){
|
||||
if (strlen(maxstr) < 2){
|
||||
clicon_err(OE_YANG, 0, "range statement: %s not on the form: <int>..<int>");
|
||||
clicon_err(OE_YANG, 0, "range statement: %s not on the form: <int>..<int>",
|
||||
ys->ys_argument);
|
||||
goto done;
|
||||
}
|
||||
minstr[maxstr-minstr] = '\0';
|
||||
|
|
@ -1499,7 +1505,7 @@ yang_expand(yang_node *yn)
|
|||
size = (yn->yn_len - i - 1)*sizeof(struct yang_stmt *);
|
||||
yn->yn_len += glen - 1;
|
||||
if (glen && (yn->yn_stmt = realloc(yn->yn_stmt, (yn->yn_len)*sizeof(yang_stmt *))) == 0){
|
||||
clicon_err(OE_YANG, errno, "%s: realloc", __FUNCTION__);
|
||||
clicon_err(OE_YANG, errno, "realloc");
|
||||
return -1;
|
||||
}
|
||||
/* Then move all existing elements up from i+1 (not uses-stmt) */
|
||||
|
|
@ -1540,10 +1546,10 @@ yang_expand(yang_node *yn)
|
|||
* Syntax parsing. A string is input and a syntax-tree is returned (or error).
|
||||
* A variable record is also returned containing a list of (global) variable values.
|
||||
* (cloned from cligen)
|
||||
* @param h CLICON handle
|
||||
* @param str String of yang statements
|
||||
* @param name Log string, typically filename
|
||||
* @param ysp Yang specification. Should ave been created by caller using yspec_new
|
||||
* @param[in] h CLICON handle
|
||||
* @param[in] str String of yang statements
|
||||
* @param[in] name Log string, typically filename
|
||||
* @param[in] ysp Yang specification. Should ave been created by caller using yspec_new
|
||||
* @retval ymod Top-level yang (sub)module
|
||||
* @retval NULL Error encountered
|
||||
* Calling order:
|
||||
|
|
@ -1554,15 +1560,17 @@ yang_expand(yang_node *yn)
|
|||
* clixon_yang_parseparse # Actual yang parsing using yacc
|
||||
*/
|
||||
static yang_stmt *
|
||||
yang_parse_str(clicon_handle h,
|
||||
char *str,
|
||||
yang_parse_str(char *str,
|
||||
const char *name, /* just for errs */
|
||||
yang_spec *yspec)
|
||||
{
|
||||
struct clicon_yang_yacc_arg yy = {0,};
|
||||
yang_stmt *ymod = NULL;
|
||||
|
||||
yy.yy_handle = h;
|
||||
if (yspec == NULL){
|
||||
clicon_err(OE_YANG, 0, "Yang parse need top level yang spec");
|
||||
goto done;
|
||||
}
|
||||
yy.yy_name = (char*)name;
|
||||
yy.yy_linenum = 1;
|
||||
yy.yy_parse_string = str;
|
||||
|
|
@ -1595,15 +1603,66 @@ yang_parse_str(clicon_handle h,
|
|||
return ymod; /* top-level (sub)module */
|
||||
}
|
||||
|
||||
/*! Read an opened file into a string and call yang string parsing
|
||||
/*! Parse yang spec from an open file descriptor
|
||||
* @param[in] fd File descriptor containing the YANG file as ASCII characters
|
||||
* @param[in] name For debug, eg filename
|
||||
* @param[in] ysp Yang specification. Should ave been created by caller using yspec_new
|
||||
* @retval ymod Top-level yang (sub)module
|
||||
* @retval NULL Error
|
||||
*/
|
||||
yang_stmt *
|
||||
yang_parse_file(int fd,
|
||||
const char *name,
|
||||
yang_spec *ysp)
|
||||
{
|
||||
char *buf = NULL;
|
||||
int i;
|
||||
int c;
|
||||
int len;
|
||||
yang_stmt *ymod = NULL;
|
||||
int ret;
|
||||
|
||||
len = BUFLEN; /* any number is fine */
|
||||
if ((buf = malloc(len)) == NULL){
|
||||
perror("pt_file malloc");
|
||||
return NULL;
|
||||
}
|
||||
memset(buf, 0, len);
|
||||
i = 0; /* position in buf */
|
||||
while (1){ /* read the whole file */
|
||||
if ((ret = read(fd, &c, 1)) < 0){
|
||||
clicon_err(OE_XML, errno, "read");
|
||||
break;
|
||||
}
|
||||
if (ret == 0)
|
||||
break; /* eof */
|
||||
if (len==i){
|
||||
if ((buf = realloc(buf, 2*len)) == NULL){
|
||||
clicon_err(OE_XML, errno, "realloc");
|
||||
goto done;
|
||||
}
|
||||
memset(buf+len, 0, len);
|
||||
len *= 2;
|
||||
}
|
||||
buf[i++] = (char)(c&0xff);
|
||||
} /* read a line */
|
||||
if ((ymod = yang_parse_str(buf, name, ysp)) < 0)
|
||||
goto done;
|
||||
done:
|
||||
if (buf)
|
||||
free(buf);
|
||||
return ymod; /* top-level (sub)module */
|
||||
}
|
||||
|
||||
/*! Open a file, read into a string and invoke yang parsing
|
||||
*
|
||||
* Similar to clicon_yang_str(), just read a file first
|
||||
* (cloned from cligen)
|
||||
* @param h CLICON handle
|
||||
* @param filename Name of file
|
||||
* @param ysp Yang specification. Should ave been created by caller using yspec_new
|
||||
* @retval ymod Top-level yang (sub)module
|
||||
* @retval NULL Error encountered
|
||||
* @param[in] h CLICON handle
|
||||
* @param[in] filename Name of file
|
||||
* @param[in] ysp Yang specification. Should ave been created by caller using yspec_new
|
||||
* @retval ymod Top-level yang (sub)module
|
||||
* @retval NULL Error encountered
|
||||
|
||||
* The database symbols are inserted in alphabetical order.
|
||||
* Calling order:
|
||||
|
|
@ -1614,57 +1673,27 @@ yang_parse_str(clicon_handle h,
|
|||
* clixon_yang_parseparse # Actual yang parsing using yacc
|
||||
*/
|
||||
static yang_stmt *
|
||||
yang_parse_file(clicon_handle h,
|
||||
const char *filename,
|
||||
yang_spec *ysp
|
||||
)
|
||||
yang_parse_filename(const char *filename,
|
||||
yang_spec *ysp)
|
||||
{
|
||||
char *buf = NULL;
|
||||
int i;
|
||||
int c;
|
||||
int len;
|
||||
yang_stmt *ymod = NULL;
|
||||
FILE *f = NULL;
|
||||
struct stat st;
|
||||
int fd = -1;
|
||||
struct stat st;
|
||||
|
||||
clicon_log(LOG_DEBUG, "Parsing yang file: %s", filename);
|
||||
if (stat(filename, &st) < 0){
|
||||
clicon_err(OE_YANG, errno, "%s not found", filename);
|
||||
goto done;
|
||||
}
|
||||
if ((f = fopen(filename, "r")) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "fopen(%s)", filename);
|
||||
if ((fd = open(filename, O_RDONLY)) < 0){
|
||||
clicon_err(OE_YANG, errno, "open(%s)", filename);
|
||||
goto done;
|
||||
}
|
||||
|
||||
len = 1024; /* any number is fine */
|
||||
if ((buf = malloc(len)) == NULL){
|
||||
perror("pt_file malloc");
|
||||
return NULL;
|
||||
}
|
||||
memset(buf, 0, len);
|
||||
|
||||
i = 0; /* position in buf */
|
||||
while (1){ /* read the whole file */
|
||||
if ((c = fgetc(f)) == EOF)
|
||||
break;
|
||||
if (len==i){
|
||||
if ((buf = realloc(buf, 2*len)) == NULL){
|
||||
fprintf(stderr, "%s: realloc: %s\n", __FUNCTION__, strerror(errno));
|
||||
goto done;
|
||||
}
|
||||
memset(buf+len, 0, len);
|
||||
len *= 2;
|
||||
}
|
||||
buf[i++] = (char)(c&0xff);
|
||||
} /* read a line */
|
||||
if ((ymod = yang_parse_str(h, buf, filename, ysp)) < 0)
|
||||
if ((ymod = yang_parse_file(fd, filename, ysp)) < 0)
|
||||
goto done;
|
||||
done:
|
||||
if (f)
|
||||
fclose(f);
|
||||
if (buf)
|
||||
free(buf);
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
return ymod; /* top-level (sub)module */
|
||||
}
|
||||
|
||||
|
|
@ -1679,8 +1708,7 @@ yang_parse_file(clicon_handle h,
|
|||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
yang_parse_find_match(clicon_handle h,
|
||||
const char *yang_dir,
|
||||
yang_parse_find_match(const char *yang_dir,
|
||||
const char *module,
|
||||
cbuf *fbuf)
|
||||
{
|
||||
|
|
@ -1724,7 +1752,7 @@ yang_parse_find_match(clicon_handle h,
|
|||
* @param[in] h CLICON handle
|
||||
* @param[in] yang_dir Directory where all YANG module files reside
|
||||
* @param[in] module Name of main YANG module. Or absolute file name.
|
||||
* @param[in] revision Optional module revision date
|
||||
* @param[in] revision Module revision date or NULL
|
||||
* @param[in] ysp Yang specification. Should have been created by caller using yspec_new
|
||||
* @retval ymod Top-level yang (sub)module
|
||||
* @retval NULL Error encountered
|
||||
|
|
@ -1737,8 +1765,7 @@ yang_parse_find_match(clicon_handle h,
|
|||
* clixon_yang_parseparse # Actual yang parsing using yacc
|
||||
*/
|
||||
static yang_stmt *
|
||||
yang_parse_recurse(clicon_handle h,
|
||||
const char *yang_dir,
|
||||
yang_parse_recurse(const char *yang_dir,
|
||||
const char *module,
|
||||
const char *revision,
|
||||
yang_spec *ysp)
|
||||
|
|
@ -1752,26 +1779,26 @@ yang_parse_recurse(clicon_handle h,
|
|||
int nr;
|
||||
|
||||
if (module[0] == '/'){
|
||||
if ((ymod = yang_parse_file(h, module, ysp)) == NULL)
|
||||
if ((ymod = yang_parse_filename(module, ysp)) == NULL)
|
||||
goto done;
|
||||
}
|
||||
else {
|
||||
if ((fbuf = cbuf_new()) == NULL){
|
||||
clicon_err(OE_YANG, errno, "%s: cbuf_new", __FUNCTION__);
|
||||
clicon_err(OE_YANG, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if (revision)
|
||||
cprintf(fbuf, "%s/%s@%s.yang", yang_dir, module, revision);
|
||||
else{
|
||||
/* No specific revision, Match a yang file */
|
||||
if ((nr = yang_parse_find_match(h, yang_dir, module, fbuf)) < 0)
|
||||
if ((nr = yang_parse_find_match(yang_dir, module, fbuf)) < 0)
|
||||
goto done;
|
||||
if (nr == 0){
|
||||
clicon_err(OE_YANG, errno, "No matching %s yang files found (expected module name or absolute filename)", module);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if ((ymod = yang_parse_file(h, cbuf_get(fbuf), ysp)) == NULL)
|
||||
if ((ymod = yang_parse_filename(cbuf_get(fbuf), ysp)) == NULL)
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
|
@ -1786,7 +1813,7 @@ yang_parse_recurse(clicon_handle h,
|
|||
subrevision = NULL;
|
||||
if (yang_find((yang_node*)ysp, Y_MODULE, modname) == NULL)
|
||||
/* recursive call */
|
||||
if (yang_parse_recurse(h, yang_dir, modname, subrevision, ysp) == NULL){
|
||||
if (yang_parse_recurse(yang_dir, modname, subrevision, ysp) == NULL){
|
||||
ymod = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -1845,7 +1872,7 @@ ys_schemanode_check(yang_stmt *ys,
|
|||
* @param[in] h CLICON handle
|
||||
* @param[in] yang_dir Directory where all YANG module files reside (except mainfile)
|
||||
* @param[in] mainmod Name of main YANG module. Or absolute file name.
|
||||
* @param[in] revision Optional main module revision date.
|
||||
* @param[in] revision Main module revision date string or NULL
|
||||
* @param[out] ysp Yang specification. Should ave been created by caller using yspec_new
|
||||
* @retval 0 Everything OK
|
||||
* @retval -1 Error encountered
|
||||
|
|
@ -1854,7 +1881,8 @@ ys_schemanode_check(yang_stmt *ys,
|
|||
* @note if mainmod is filename, revision is not considered.
|
||||
* Calling order:
|
||||
* yang_parse # Parse top-level yang module. Expand and populate yang tree
|
||||
* yang_parse_recurse # Parse one yang module, go through its (sub)modules, parse them and then recursively parse them
|
||||
* yang_parse_recurse # Parse one yang module, go through its (sub)modules,
|
||||
* parse them and then recursively parse them
|
||||
* yang_parse_file # Read yang file into a string
|
||||
* yang_parse_str # Set up yacc parser and call it given a string
|
||||
* clixon_yang_parseparse # Actual yang parsing using yacc
|
||||
|
|
@ -1870,7 +1898,7 @@ yang_parse(clicon_handle h,
|
|||
yang_stmt *ymod; /* Top-level yang (sub)module */
|
||||
|
||||
/* Step 1: parse from text to yang parse-tree. */
|
||||
if ((ymod = yang_parse_recurse(h, yang_dir, mainmodule, revision, ysp)) == NULL)
|
||||
if ((ymod = yang_parse_recurse(yang_dir, mainmodule, revision, ysp)) == NULL)
|
||||
goto done;
|
||||
/* Add top module name as dbspec-name */
|
||||
clicon_dbspec_name_set(h, ymod->ys_argument);
|
||||
|
|
@ -2080,13 +2108,13 @@ yang_abs_schema_nodeid(yang_spec *yspec,
|
|||
goto done;
|
||||
}
|
||||
if ((vec = clicon_strsep(schema_nodeid, "/", &nvec)) == NULL){
|
||||
clicon_err(OE_YANG, errno, "%s: strsep", __FUNCTION__);
|
||||
clicon_err(OE_YANG, errno, "strsep");
|
||||
goto done;
|
||||
}
|
||||
/* Assume schema nodeid looks like: "/prefix:id[/prefix:id]*" */
|
||||
if (nvec < 2){
|
||||
clicon_err(OE_YANG, 0, "%s: NULL or truncated path: %s",
|
||||
__FUNCTION__, schema_nodeid);
|
||||
clicon_err(OE_YANG, 0, "NULL or truncated path: %s",
|
||||
schema_nodeid);
|
||||
goto done;
|
||||
}
|
||||
/* split <prefix>:<id> */
|
||||
|
|
@ -2095,7 +2123,7 @@ yang_abs_schema_nodeid(yang_spec *yspec,
|
|||
goto ok;
|
||||
}
|
||||
if ((prefix = strdup(vec[1])) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "%s: strdup", __FUNCTION__);
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
prefix[id-vec[1]] = '\0';
|
||||
|
|
@ -2183,7 +2211,7 @@ ys_parse(yang_stmt *ys,
|
|||
|
||||
assert(ys->ys_cv == NULL); /* Cv:s are parsed in different places, difficult to separate */
|
||||
if ((ys->ys_cv = cv_new(cvtype)) == NULL){
|
||||
clicon_err(OE_YANG, errno, "%s: cv_new", __FUNCTION__);
|
||||
clicon_err(OE_YANG, errno, "cv_new");
|
||||
goto done;
|
||||
}
|
||||
if ((cvret = cv_parse1(ys->ys_argument, ys->ys_cv, &reason)) < 0){ /* error */
|
||||
|
|
@ -2252,7 +2280,7 @@ ys_parse_sub(yang_stmt *ys,
|
|||
goto done;
|
||||
}
|
||||
if ((ys->ys_cv = cv_new(CGV_STRING)) == NULL){
|
||||
clicon_err(OE_YANG, errno, "%s: cv_new", __FUNCTION__);
|
||||
clicon_err(OE_YANG, errno, "cv_new");
|
||||
goto done;
|
||||
}
|
||||
if ((cvret = cv_parse1(extra, ys->ys_cv, &reason)) < 0){ /* error */
|
||||
|
|
@ -2334,9 +2362,9 @@ yang_spec_netconf(clicon_handle h)
|
|||
}
|
||||
|
||||
/*! Read, parse and save application yang specification as option
|
||||
* @param h clicon handle
|
||||
* @param f file to print to (if printspec enabled)
|
||||
* @param printspec print database (YANG) specification as read from file
|
||||
* @param[in] h clicon handle
|
||||
* @param[in] f file to print to (if printspec enabled)
|
||||
* @param[in] printspec print database (YANG) specification as read from file
|
||||
*/
|
||||
yang_spec*
|
||||
yang_spec_main(clicon_handle h)
|
||||
|
|
@ -2346,7 +2374,7 @@ yang_spec_main(clicon_handle h)
|
|||
char *yang_module;
|
||||
char *yang_revision;
|
||||
|
||||
if ((yang_dir = clicon_yang_dir(h)) == NULL){
|
||||
if ((yang_dir = clicon_yang_dir(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "CLICON_YANG_DIR option not set");
|
||||
goto done;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue