Added connect/disconnect/getopt/setopt and handle to xmldb API; Added datastore 'text'; Moved apps/dbctrl to datastore/

This commit is contained in:
Olof hagsand 2017-04-15 13:53:58 +02:00
parent 85af4342dc
commit d26a801bc0
25 changed files with 1501 additions and 912 deletions

View file

@ -58,18 +58,17 @@
#define handle(h) (assert(clicon_handle_check(h)==0),(struct clicon_handle *)(h))
/*
* clicon_handle
* Internal structire of basic handle. Also header of all other handles.
* see struct clicon_cli_handle, struct clicon_backend_handle, etc
/*! Internal structure of basic handle. Also header of all other handles.
* @note If you change here, you must also change the structs below:
* @see struct cli_handle, struct backend_handle
*/
struct clicon_handle {
int ch_magic; /* magic (HDR) */
clicon_hash_t *ch_copt; /* clicon option list (HDR) */
clicon_hash_t *ch_data; /* internal clicon data (HDR) */
void *ch_xmldb; /* XMLDB storage handle, uie xmldb_handle */
};
/*! Internal call to allocate a CLICON handle.
*
* There may be different variants of handles with some common options.
@ -166,3 +165,31 @@ clicon_data(clicon_handle h)
return ch->ch_data;
}
/*! Set or reset XMLDB storage handle
* @param[in] h Clicon handle
* @param[in] xh XMLDB storage handle. If NULL reset it
* @note Just keep note of it, dont allocate it or so.
*/
int
clicon_handle_xmldb_set(clicon_handle h,
void *xh)
{
struct clicon_handle *ch = handle(h);
ch->ch_xmldb = xh;
return 0;
}
/*! Get XMLDB storage handle
* @param[in] h Clicon handle
* @retval xh XMLDB storage handle. If not connected return NULL
*/
void *
clicon_handle_xmldb_get(clicon_handle h)
{
struct clicon_handle *ch = handle(h);
return ch->ch_xmldb;
}

View file

@ -1008,6 +1008,7 @@ FSM(char *tag,
* Note, xt will add a top-level symbol called "top" meaning that <tree../> will look as:
* <top><tree.../></tree>
* XXX: There is a potential leak here on some return values.
* XXX: What happens if endtag is different?
* May block
*/
int
@ -1023,15 +1024,16 @@ clicon_xml_parse_file(int fd,
int maxbuf = BUFLEN;
int endtaglen = strlen(endtag);
int state = 0;
int oldmaxbuf;
if (endtag == NULL){
clicon_err(OE_XML, 0, "%s: endtag required\n", __FUNCTION__);
return -1;
goto done;
}
*cx = NULL;
if ((xmlbuf = malloc(maxbuf)) == NULL){
clicon_err(OE_XML, errno, "%s: malloc", __FUNCTION__);
return -1;
goto done;
}
memset(xmlbuf, 0, maxbuf);
ptr = xmlbuf;
@ -1050,24 +1052,33 @@ clicon_xml_parse_file(int fd,
state = 0;
if ((*cx = xml_new("top", NULL)) == NULL)
break;
if (xml_parse(ptr, *cx) < 0)
if (xml_parse(ptr, *cx) < 0){
goto done;
return -1;
}
break;
}
if (len>=maxbuf-1){ /* Space: one for the null character */
int oldmaxbuf = maxbuf;
oldmaxbuf = maxbuf;
maxbuf *= 2;
if ((xmlbuf = realloc(xmlbuf, maxbuf)) == NULL){
clicon_err(OE_XML, errno, "%s: realloc", __FUNCTION__);
return -1;
goto done;
}
memset(xmlbuf+oldmaxbuf, 0, maxbuf-oldmaxbuf);
ptr = xmlbuf;
}
} /* while */
free(xmlbuf);
return (*cx)?0:-1;
retval = 0;
done:
if (retval < 0 && *cx){
free(*cx);
*cx = NULL;
}
if (xmlbuf)
free(xmlbuf);
return retval;
// return (*cx)?0:-1;
}
/*! Read an XML definition from string and parse it into a parse-tree.
@ -1461,8 +1472,12 @@ xml_body_uint32(cxobj *xb,
}
/*! Map xml operation from string to enumeration
* @param[in] xn XML node
* @param[out] op "operation" attribute may change operation
* @param[in] opstr String, eg "merge"
* @param[out] op Enumeration, eg OP_MERGE
* @code
* enum operation_type op;
* xml_operation("replace", &op)
* @endcode
*/
int
xml_operation(char *opstr,
@ -1487,6 +1502,14 @@ xml_operation(char *opstr,
return 0;
}
/*! Map xml operation from enumeration to string
* @param[in] op enumeration operation, eg OP_MERGE,...
* @retval str String, eg "merge". Static string, no free necessary
* @code
* enum operation_type op;
* xml_operation("replace", &op)
* @endcode
*/
char *
xml_operation2str(enum operation_type op)
{
@ -1510,3 +1533,4 @@ xml_operation2str(enum operation_type op)
return "none";
}
}

View file

@ -58,6 +58,8 @@
#include "clixon_hash.h"
#include "clixon_handle.h"
#include "clixon_xml.h"
#include "clixon_yang.h"
#include "clixon_options.h"
#include "clixon_xml_db.h"
static struct xmldb_api *_xa_api = NULL;
@ -65,12 +67,13 @@ static struct xmldb_api *_xa_api = NULL;
/*! Load a specific plugin, call its init function and add it to plugins list
* If init function fails (not found, wrong version, etc) print a log and dont
* add it.
* @param[in] name Name of plugin
* @param[in] name Filename (complete path) of plugin
* @param[in] filename Actual filename with path
* @param[out] plugin Plugin data structure for invoking. Dealloc with free
*/
int
xmldb_plugin_load(char *filename)
xmldb_plugin_load(clicon_handle h,
char *filename)
{
int retval = -1;
char *dlerrcode;
@ -117,11 +120,179 @@ xmldb_plugin_load(char *filename)
goto done;
}
int
xmldb_get(clicon_handle h, char *db, char *xpath,
cxobj **xtop, cxobj ***xvec, size_t *xlen)
/*! XXX: fixme */
int
xmldb_plugin_unload(clicon_handle h)
{
int retval = -1;
return 0;
}
/*! Connect to a datastore plugin
* @retval handle Use this handle for other API calls
* @retval NULL Error
* @note You can do several connects, and have multiple connections to the same
* datastore. Note also that the xmldb handle is hidden in the clicon
* handle, the clixon user does not need to handle it. Note also that
* typically only the backend invokes the datastore.
* XXX what args does connect have?
*/
int
xmldb_connect(clicon_handle h)
{
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
goto done;
}
if (_xa_api->xa_connect_fn == NULL){
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
if ((xh = _xa_api->xa_connect_fn()) == NULL)
goto done;
clicon_handle_xmldb_set(h, xh);
retval = 0;
done:
return retval;
}
/*! Disconnect from a datastore plugin and deallocate handle
* @param[in] handle Disconect and deallocate from this handle
* @retval 0 OK
*/
int
xmldb_disconnect(clicon_handle h)
{
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
goto done;
}
if (_xa_api->xa_disconnect_fn == NULL){
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Already disconnected from datastore plugin");
goto done;
}
if (_xa_api->xa_disconnect_fn(xh) < 0)
goto done;
clicon_handle_xmldb_set(h, NULL);
retval = 0;
done:
return retval;
}
/*! Get value of generic plugin option. Type of value is givenby context
* @param[in] xh XMLDB handle
* @param[in] optname Option name
* @param[out] value Pointer to Value of option
* @retval 0 OK
* @retval -1 Error
*/
int
xmldb_getopt(clicon_handle h,
char *optname,
void **value)
{
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
goto done;
}
if (_xa_api->xa_getopt_fn == NULL){
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval = _xa_api->xa_getopt_fn(xh, optname, value);
done:
return retval;
}
/*! Set value of generic plugin option. Type of value is givenby context
* @param[in] xh XMLDB handle
* @param[in] optname Option name
* @param[in] value Value of option
* @retval 0 OK
* @retval -1 Error
*/
int
xmldb_setopt(clicon_handle h,
char *optname,
void *value)
{
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
goto done;
}
if (_xa_api->xa_setopt_fn == NULL){
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval = _xa_api->xa_setopt_fn(xh, optname, value);
done:
return retval;
}
/*! Get content of database using xpath. return a set of matching sub-trees
* The function returns a minimal tree that includes all sub-trees that match
* xpath.
* @param[in] h Clicon handle
* @param[in] dbname Name of database to search in (filename including dir path
* @param[in] xpath String with XPATH syntax. or NULL for all
* @param[out] xtop Single XML tree which xvec points to. Free with xml_free()
* @param[out] xvec Vector of xml trees. Free after use.
* @param[out] xlen Length of vector.
* @retval 0 OK
* @retval -1 Error
* @code
* cxobj *xt;
* cxobj **xvec;
* size_t xlen;
* if (xmldb_get(xh, "running", "/interfaces/interface[name="eth"]",
* &xt, &xvec, &xlen) < 0)
* err;
* for (i=0; i<xlen; i++){
* xn = xv[i];
* ...
* }
* xml_free(xt);
* free(xvec);
* @endcode
* @note if xvec is given, then purge tree, if not return whole tree.
* @see xpath_vec
* @see xmldb_get
*/
int
xmldb_get(clicon_handle h,
char *db,
char *xpath,
cxobj **xtop,
cxobj ***xvec,
size_t *xlen)
{
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
@ -131,7 +302,11 @@ xmldb_get(clicon_handle h, char *db, char *xpath,
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
retval = _xa_api->xa_get_fn(h, db, xpath, xtop, xvec, xlen);
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval = _xa_api->xa_get_fn(xh, db, xpath, xtop, xvec, xlen);
done:
return retval;
}
@ -152,16 +327,20 @@ xmldb_get(clicon_handle h, char *db, char *xpath,
* cxobj *xt;
* if (clicon_xml_parse_str("<a>17</a>", &xt) < 0)
* err;
* if (xmldb_put(h, "running", OP_MERGE, NULL, xt) < 0)
* if (xmldb_put(xh, "running", OP_MERGE, NULL, xt) < 0)
* err;
* @endcode
* @see xmldb_put_xkey for single key
*/
int
xmldb_put(clicon_handle h, char *db, enum operation_type op,
char *api_path, cxobj *xt)
xmldb_put(clicon_handle h,
char *db,
enum operation_type op,
char *api_path,
cxobj *xt)
{
int retval = -1;
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
@ -171,32 +350,11 @@ xmldb_put(clicon_handle h, char *db, enum operation_type op,
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
retval = _xa_api->xa_put_fn(h, db, op, api_path, xt);
done:
return retval;
}
/*! Raw dump of database, in internal format (depends on datastore)
* @param[in] f File
* @param[in] dbfile File-name of database. This is a local file
* @param[in] pattern Key regexp, eg "^.*$"
*/
int
xmldb_dump(FILE *f,
char *dbfilename,
char *pattern)
{
int retval = -1;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
if (_xa_api->xa_dump_fn == NULL){
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
retval = _xa_api->xa_dump_fn(f, dbfilename, pattern);
retval = _xa_api->xa_put_fn(xh, db, op, api_path, xt);
done:
return retval;
}
@ -209,9 +367,12 @@ xmldb_dump(FILE *f,
* @retval 0 OK
*/
int
xmldb_copy(clicon_handle h, char *from, char *to)
xmldb_copy(clicon_handle h,
char *from,
char *to)
{
int retval = -1;
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
@ -221,7 +382,11 @@ xmldb_copy(clicon_handle h, char *from, char *to)
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
retval = _xa_api->xa_copy_fn(h, from, to);
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval = _xa_api->xa_copy_fn(xh, from, to);
done:
return retval;
}
@ -234,9 +399,12 @@ xmldb_copy(clicon_handle h, char *from, char *to)
* @retval 0 OK
*/
int
xmldb_lock(clicon_handle h, char *db, int pid)
xmldb_lock(clicon_handle h,
char *db,
int pid)
{
int retval = -1;
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
@ -246,7 +414,11 @@ xmldb_lock(clicon_handle h, char *db, int pid)
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
retval = _xa_api->xa_lock_fn(h, db, pid);
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval = _xa_api->xa_lock_fn(xh, db, pid);
done:
return retval;
}
@ -260,9 +432,12 @@ xmldb_lock(clicon_handle h, char *db, int pid)
* Assume all sanity checks have been made
*/
int
xmldb_unlock(clicon_handle h, char *db, int pid)
xmldb_unlock(clicon_handle h,
char *db,
int pid)
{
int retval = -1;
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
@ -272,7 +447,11 @@ xmldb_unlock(clicon_handle h, char *db, int pid)
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
retval = _xa_api->xa_unlock_fn(h, db, pid);
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval = _xa_api->xa_unlock_fn(xh, db, pid);
done:
return retval;
}
@ -284,9 +463,11 @@ xmldb_unlock(clicon_handle h, char *db, int pid)
* @retval 0 OK
*/
int
xmldb_unlock_all(clicon_handle h, int pid)
xmldb_unlock_all(clicon_handle h,
int pid)
{
int retval = -1;
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
@ -296,7 +477,11 @@ xmldb_unlock_all(clicon_handle h, int pid)
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
retval =_xa_api->xa_unlock_all_fn(h, pid);
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval =_xa_api->xa_unlock_all_fn(xh, pid);
done:
return retval;
}
@ -309,9 +494,11 @@ xmldb_unlock_all(clicon_handle h, int pid)
* @retval >0 Id of locker
*/
int
xmldb_islocked(clicon_handle h, char *db)
xmldb_islocked(clicon_handle h,
char *db)
{
int retval = -1;
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
@ -321,7 +508,11 @@ xmldb_islocked(clicon_handle h, char *db)
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
retval =_xa_api->xa_islocked_fn(h, db);
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval =_xa_api->xa_islocked_fn(xh, db);
done:
return retval;
}
@ -334,9 +525,11 @@ xmldb_islocked(clicon_handle h, char *db)
* @retval 1 Yes it exists
*/
int
xmldb_exists(clicon_handle h, char *db)
xmldb_exists(clicon_handle h,
char *db)
{
int retval = -1;
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
@ -346,7 +539,11 @@ xmldb_exists(clicon_handle h, char *db)
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
retval = _xa_api->xa_exists_fn(h, db);
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval = _xa_api->xa_exists_fn(xh, db);
done:
return retval;
}
@ -358,9 +555,11 @@ xmldb_exists(clicon_handle h, char *db)
* @retval 0 OK
*/
int
xmldb_delete(clicon_handle h, char *db)
xmldb_delete(clicon_handle h,
char *db)
{
int retval = -1;
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
@ -370,21 +569,27 @@ xmldb_delete(clicon_handle h, char *db)
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
retval = _xa_api->xa_delete_fn(h, db);
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval = _xa_api->xa_delete_fn(xh, db);
done:
return retval;
}
/*! Initialize database
/*! Initialize database. Open database for writing.
* @param[in] h Clicon handle
* @param[in] db Database
* @retval 0 OK
* @retval -1 Error
*/
int
xmldb_init(clicon_handle h, char *db)
xmldb_init(clicon_handle h,
char *db)
{
int retval = -1;
int retval = -1;
xmldb_handle xh;
if (_xa_api == NULL){
clicon_err(OE_DB, 0, "No xmldb plugin");
@ -394,7 +599,11 @@ xmldb_init(clicon_handle h, char *db)
clicon_err(OE_DB, 0, "No xmldb function");
goto done;
}
retval = _xa_api->xa_init_fn(h, db);
if ((xh = clicon_handle_xmldb_get(h)) == NULL){
clicon_err(OE_DB, 0, "Not connected to datastore plugin");
goto done;
}
retval = _xa_api->xa_init_fn(xh, db);
done:
return retval;
}

View file

@ -1074,3 +1074,176 @@ xmlkeyfmt2xpath(char *xkfmt,
cbuf_free(cb);
return retval;
}
/*! Prune everything that has not been marked
* @param[in] xt XML tree with some node marked
* @param[out] upmark Set if a child (recursively) has marked set.
* The function removes all branches that does not contain a marked child
* XXX: maybe key leafs should not be purged if list is not purged?
* XXX: consider move to clicon_xml
*/
int
xml_tree_prune_unmarked(cxobj *xt,
int *upmark)
{
int retval = -1;
int submark;
int mark;
cxobj *x;
cxobj *xprev;
mark = 0;
x = NULL;
xprev = x = NULL;
while ((x = xml_child_each(xt, x, CX_ELMNT)) != NULL) {
if (xml_flag(x, XML_FLAG_MARK)){
mark++;
xprev = x;
continue; /* mark and stop here */
}
if (xml_tree_prune_unmarked(x, &submark) < 0)
goto done;
if (submark)
mark++;
else{ /* Safe with xml_child_each if last */
if (xml_purge(x) < 0)
goto done;
x = xprev;
}
xprev = x;
}
retval = 0;
done:
if (upmark)
*upmark = mark;
return retval;
}
/*! Add default values (if not set)
* @param[in] xt XML tree with some node marked
*/
int
xml_default(cxobj *xt,
void *arg)
{
int retval = -1;
yang_stmt *ys;
yang_stmt *y;
int i;
cxobj *xc;
cxobj *xb;
char *str;
ys = (yang_stmt*)xml_spec(xt);
/* Check leaf defaults */
if (ys->ys_keyword == Y_CONTAINER || ys->ys_keyword == Y_LIST){
for (i=0; i<ys->ys_len; i++){
y = ys->ys_stmt[i];
if (y->ys_keyword != Y_LEAF)
continue;
assert(y->ys_cv);
if (!cv_flag(y->ys_cv, V_UNSET)){ /* Default value exists */
if (!xml_find(xt, y->ys_argument)){
if ((xc = xml_new_spec(y->ys_argument, xt, y)) == NULL)
goto done;
if ((xb = xml_new("body", xc)) == NULL)
goto done;
xml_type_set(xb, CX_BODY);
if ((str = cv2str_dup(y->ys_cv)) == NULL){
clicon_err(OE_UNIX, errno, "cv2str_dup");
goto done;
}
if (xml_value_set(xb, str) < 0)
goto done;
free(str);
}
}
}
}
retval = 0;
done:
return retval;
}
/*! Order XML children according to YANG
* @param[in] xt XML top of tree
*/
int
xml_order(cxobj *xt,
void *arg)
{
int retval = -1;
yang_stmt *y;
yang_stmt *yc;
int i;
int j0;
int j;
cxobj *xc;
cxobj *xj;
char *yname; /* yang child name */
char *xname; /* xml child name */
y = (yang_stmt*)xml_spec(xt);
j0 = 0;
/* Go through xml children and ensure they are same order as yspec children */
for (i=0; i<y->ys_len; i++){
yc = y->ys_stmt[i];
if (!yang_is_syntax(yc))
continue;
yname = yc->ys_argument;
/* First go thru xml children with same name */
for (; j0<xml_child_nr(xt); j0++){
xc = xml_child_i(xt, j0);
if (xml_type(xc) != CX_ELMNT)
continue;
xname = xml_name(xc);
if (strcmp(xname, yname))
break;
}
/* Now we have children not with same name */
for (j=j0; j<xml_child_nr(xt); j++){
xc = xml_child_i(xt, j);
if (xml_type(xc) != CX_ELMNT)
continue;
xname = xml_name(xc);
if (strcmp(xname, yname))
continue;
/* reorder */
xj = xml_child_i(xt, j0);
xml_child_i_set(xt, j0, xc);
xml_child_i_set(xt, j, xj);
j0++;
}
}
retval = 0;
// done:
return retval;
}
/*! Sanitize an xml tree: xml node has matching yang_stmt pointer
* @param[in] xt XML top of tree
*/
int
xml_sanity(cxobj *xt,
void *arg)
{
int retval = -1;
yang_stmt *ys;
char *name;
ys = (yang_stmt*)xml_spec(xt);
name = xml_name(xt);
if (ys==NULL){
clicon_err(OE_XML, 0, "No spec for xml node %s", name);
goto done;
}
if (strstr(ys->ys_argument, name)==NULL){
clicon_err(OE_XML, 0, "xml node name '%s' does not match yang spec arg '%s'",
name, ys->ys_argument);
goto done;
}
retval = 0;
done:
return retval;
}

View file

@ -1540,11 +1540,11 @@ yang_parse1(clicon_handle h,
/*! Parse top yang module including all its sub-modules. Expand and populate yang tree
*
* @param h CLICON handle
* @param yang_dir Directory where all YANG module files reside
* @param module Name of main YANG module. More modules may be parsed if imported
* @param revision Optional module revision date
* @param ysp Yang specification. Should ave been created by caller using yspec_new
* @param[in] h CLICON handle
* @param[in] yang_dir Directory where all YANG module files reside
* @param[in] module Name of main YANG module. More modules may be parsed if imported
* @param[in] revision Optional module revision date
* @param[out] ysp Yang specification. Should ave been created by caller using yspec_new
* @retval 0 Everything OK
* @retval -1 Error encountered
* The database symbols are inserted in alphabetical order.