commit xpath
This commit is contained in:
parent
554c1cb9de
commit
9bd941ab76
14 changed files with 306 additions and 130 deletions
19
Makefile.in
19
Makefile.in
|
|
@ -42,7 +42,7 @@ LIBS = @LIBS@
|
||||||
INCLUDES = -I. -I@srcdir@ @INCLUDES@
|
INCLUDES = -I. -I@srcdir@ @INCLUDES@
|
||||||
SHELL = /bin/sh
|
SHELL = /bin/sh
|
||||||
|
|
||||||
SUBDIRS = lib apps include doc etc
|
SUBDIRS = lib apps include etc
|
||||||
|
|
||||||
.PHONY: doc all clean depend $(SUBDIRS) install loc TAGS .config.status
|
.PHONY: doc all clean depend $(SUBDIRS) install loc TAGS .config.status
|
||||||
|
|
||||||
|
|
@ -52,7 +52,7 @@ $(SUBDIRS):
|
||||||
(cd $@ && $(MAKE) $(MFLAGS) all)
|
(cd $@ && $(MAKE) $(MFLAGS) all)
|
||||||
|
|
||||||
depend:
|
depend:
|
||||||
for i in $(SUBDIRS) example; \
|
for i in $(SUBDIRS) doc example; \
|
||||||
do (cd $$i && $(MAKE) $(MFLAGS) depend); done
|
do (cd $$i && $(MAKE) $(MFLAGS) depend); done
|
||||||
|
|
||||||
# template clicon.conf file
|
# template clicon.conf file
|
||||||
|
|
@ -63,7 +63,7 @@ clicon.mk: clicon.mk.cpp
|
||||||
$(CPP) -P -traditional-cpp -x assembler-with-cpp -Dprefix=$(prefix) -Dlocalstatedir=$(localstatedir) -Dsysconfdir=$(sysconfdir) -Ddatadir=$(datadir) -Dlibdir=$(libdir) $< > $@
|
$(CPP) -P -traditional-cpp -x assembler-with-cpp -Dprefix=$(prefix) -Dlocalstatedir=$(localstatedir) -Dsysconfdir=$(sysconfdir) -Ddatadir=$(datadir) -Dlibdir=$(libdir) $< > $@
|
||||||
|
|
||||||
install: clicon.conf.cpp clicon.mk
|
install: clicon.conf.cpp clicon.mk
|
||||||
for i in $(SUBDIRS); \
|
for i in $(SUBDIRS) doc; \
|
||||||
do (cd $$i && $(MAKE) $(MFLAGS) $@); done; \
|
do (cd $$i && $(MAKE) $(MFLAGS) $@); done; \
|
||||||
install -d -m 755 $(DESTDIR)$(datadir)/clicon
|
install -d -m 755 $(DESTDIR)$(datadir)/clicon
|
||||||
install -m 755 clicon.conf.cpp $(DESTDIR)$(datadir)/clicon
|
install -m 755 clicon.conf.cpp $(DESTDIR)$(datadir)/clicon
|
||||||
|
|
@ -71,19 +71,18 @@ install: clicon.conf.cpp clicon.mk
|
||||||
echo "Install for compilation by: make install-include"
|
echo "Install for compilation by: make install-include"
|
||||||
|
|
||||||
install-include:
|
install-include:
|
||||||
for i in $(SUBDIRS); \
|
for i in $(SUBDIRS) doc; \
|
||||||
do (cd $$i && $(MAKE) $(MFLAGS) $@); done; \
|
do (cd $$i && $(MAKE) $(MFLAGS) $@); done; \
|
||||||
echo "To install example app: cd example; make; make install"
|
echo "To install example app: cd example; make; make install"
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
for i in $(SUBDIRS) example; \
|
for i in $(SUBDIRS) doc example; \
|
||||||
do (cd $$i && $(MAKE) $(MFLAGS) $@); done;
|
do (cd $$i && $(MAKE) $(MFLAGS) $@); done;
|
||||||
rm -f $(datadir)/clicon/clicon.conf.cpp
|
rm -f $(datadir)/clicon/clicon.conf.cpp
|
||||||
rm -f $(datadir)/clicon/clicon.mk
|
rm -f $(datadir)/clicon/clicon.mk
|
||||||
|
|
||||||
# Overrides SUBDIRS above
|
doc:
|
||||||
#doc:
|
cd $@; $(MAKE) $(MFLAGS) $@
|
||||||
# cd $@; $(MAKE) $(MFLAGS) $@
|
|
||||||
|
|
||||||
config.status: configure
|
config.status: configure
|
||||||
$(SHELL) config.status --recheck
|
$(SHELL) config.status --recheck
|
||||||
|
|
@ -92,14 +91,14 @@ configure: configure.ac
|
||||||
cd $(srcdir) && autoconf
|
cd $(srcdir) && autoconf
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
for i in $(SUBDIRS) example; \
|
for i in $(SUBDIRS) doc example; \
|
||||||
do (cd $$i && $(MAKE) $(MFLAGS) $@); done;
|
do (cd $$i && $(MAKE) $(MFLAGS) $@); done;
|
||||||
|
|
||||||
distclean:
|
distclean:
|
||||||
rm -f Makefile TAGS config.status config.log *~ .depend
|
rm -f Makefile TAGS config.status config.log *~ .depend
|
||||||
rm -rf Makefile autom4te.cache
|
rm -rf Makefile autom4te.cache
|
||||||
rm -rf clicon.conf.cpp clicon.mk
|
rm -rf clicon.conf.cpp clicon.mk
|
||||||
for i in $(SUBDIRS) example; \
|
for i in $(SUBDIRS) doc example; \
|
||||||
do (cd $$i && $(MAKE) $(MFLAGS) $@); done
|
do (cd $$i && $(MAKE) $(MFLAGS) $@); done
|
||||||
|
|
||||||
# Lines of code
|
# Lines of code
|
||||||
|
|
|
||||||
|
|
@ -126,8 +126,8 @@ candidate_commit(clicon_handle h,
|
||||||
char *running)
|
char *running)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
// int i, j;
|
int i;
|
||||||
// int failed = 0;
|
cxobj *xn;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
void *firsterr = NULL;
|
void *firsterr = NULL;
|
||||||
yang_spec *yspec;
|
yang_spec *yspec;
|
||||||
|
|
@ -171,6 +171,25 @@ candidate_commit(clicon_handle h,
|
||||||
goto done;
|
goto done;
|
||||||
if (debug)
|
if (debug)
|
||||||
transaction_print(stderr, td);
|
transaction_print(stderr, td);
|
||||||
|
/* Mark as changed in tree */
|
||||||
|
for (i=0; i<td->td_dlen; i++){ /* Also down */
|
||||||
|
xn = td->td_dvec[i];
|
||||||
|
xml_flag_set(xn, XML_FLAG_DEL);
|
||||||
|
xml_apply(xn, CX_ELMNT, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_DEL);
|
||||||
|
}
|
||||||
|
for (i=0; i<td->td_alen; i++){ /* Also down */
|
||||||
|
xn = td->td_avec[i];
|
||||||
|
xml_flag_set(xn, XML_FLAG_ADD);
|
||||||
|
xml_apply(xn, CX_ELMNT, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_ADD);
|
||||||
|
}
|
||||||
|
for (i=0; i<td->td_clen; i++){ /* Also up */
|
||||||
|
xn = td->td_scvec[i];
|
||||||
|
xml_flag(xn, XML_FLAG_CHANGE);
|
||||||
|
xml_apply_ancestor(xn, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_CHANGE);
|
||||||
|
xn = td->td_tcvec[i];
|
||||||
|
xml_flag_set(xn, XML_FLAG_CHANGE);
|
||||||
|
xml_apply_ancestor(xn, (xml_applyfn_t*)xml_flag_set, (void*)XML_FLAG_CHANGE);
|
||||||
|
}
|
||||||
|
|
||||||
/* 4. Call plugin transaction start callbacks */
|
/* 4. Call plugin transaction start callbacks */
|
||||||
if (plugin_transaction_begin(h, td) < 0)
|
if (plugin_transaction_begin(h, td) < 0)
|
||||||
|
|
@ -236,6 +255,8 @@ candidate_validate(clicon_handle h,
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
yang_spec *yspec;
|
yang_spec *yspec;
|
||||||
transaction_data_t *td = NULL;
|
transaction_data_t *td = NULL;
|
||||||
|
int i;
|
||||||
|
cxobj *xn;
|
||||||
|
|
||||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||||
|
|
@ -277,6 +298,22 @@ candidate_validate(clicon_handle h,
|
||||||
if (debug)
|
if (debug)
|
||||||
transaction_print(stderr, td);
|
transaction_print(stderr, td);
|
||||||
|
|
||||||
|
/* Mark as changed in tree */
|
||||||
|
for (i=0; i<td->td_dlen; i++){ /* Also down */
|
||||||
|
xn = td->td_dvec[i];
|
||||||
|
xml_flag_set(xn, XML_FLAG_DEL);
|
||||||
|
}
|
||||||
|
for (i=0; i<td->td_alen; i++){ /* Also down */
|
||||||
|
xn = td->td_avec[i];
|
||||||
|
xml_flag_set(xn, XML_FLAG_ADD);
|
||||||
|
}
|
||||||
|
for (i=0; i<td->td_clen; i++){ /* Also up */
|
||||||
|
xn = td->td_scvec[i];
|
||||||
|
xml_flag_set(xn, XML_FLAG_CHANGE);
|
||||||
|
xn = td->td_tcvec[i];
|
||||||
|
xml_flag(xn, XML_FLAG_CHANGE);
|
||||||
|
}
|
||||||
|
|
||||||
/* 4. Call plugin start transaction callbacks */
|
/* 4. Call plugin start transaction callbacks */
|
||||||
if (plugin_transaction_begin(h, td) < 0)
|
if (plugin_transaction_begin(h, td) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
||||||
|
|
@ -1492,7 +1492,7 @@ show_conf_xpath(clicon_handle h, cvec *cvv, cg_var *arg)
|
||||||
cg_var *cv;
|
cg_var *cv;
|
||||||
cxobj *xt = NULL;
|
cxobj *xt = NULL;
|
||||||
cxobj **xv = NULL;
|
cxobj **xv = NULL;
|
||||||
int xlen;
|
size_t xlen;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (arg == NULL || (str = cv_string_get(arg)) == NULL){
|
if (arg == NULL || (str = cv_string_get(arg)) == NULL){
|
||||||
|
|
@ -1516,7 +1516,7 @@ show_conf_xpath(clicon_handle h, cvec *cvv, cg_var *arg)
|
||||||
cv = cvec_find_var(cvv, "xpath");
|
cv = cvec_find_var(cvv, "xpath");
|
||||||
xpath = cv_string_get(cv);
|
xpath = cv_string_get(cv);
|
||||||
yspec = clicon_dbspec_yang(h);
|
yspec = clicon_dbspec_yang(h);
|
||||||
if (xmldb_get_xpath(dbname, xpath, yspec, &xt, &xv, &xlen) < 0)
|
if (xmldb_get_vec(dbname, xpath, yspec, &xt, &xv, &xlen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
for (i=0; i<xlen; i++)
|
for (i=0; i<xlen; i++)
|
||||||
clicon_xml2file(stdout, xv[i], 0, 1);
|
clicon_xml2file(stdout, xv[i], 0, 1);
|
||||||
|
|
|
||||||
|
|
@ -222,7 +222,7 @@ netconf_xpath(cxobj *xsearch,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *selector;
|
char *selector;
|
||||||
cxobj **xv;
|
cxobj **xv;
|
||||||
int xlen;
|
size_t xlen;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if ((selector = xml_find_value(xfilter, "select")) == NULL){
|
if ((selector = xml_find_value(xfilter, "select")) == NULL){
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ DOXYFILE_ENCODING = UTF-8
|
||||||
# title of most generated pages and in a few other places.
|
# title of most generated pages and in a few other places.
|
||||||
# The default value is: My Project.
|
# The default value is: My Project.
|
||||||
|
|
||||||
PROJECT_NAME = "CLICON"
|
PROJECT_NAME = "CliXoN"
|
||||||
|
|
||||||
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
|
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
|
||||||
# could be handy for archiving the generated documentation or if some version
|
# could be handy for archiving the generated documentation or if some version
|
||||||
|
|
|
||||||
144
doc/FAQ.txt
144
doc/FAQ.txt
|
|
@ -1,86 +1,140 @@
|
||||||
Frequently Asked Questions - Clixon
|
Frequently Asked Questions - CliXon
|
||||||
===================================
|
===================================
|
||||||
|
|
||||||
Q: What is the best way of understanding Clixon?
|
Q: What is CliXon?
|
||||||
A: Run the ietf yang routing example.
|
------------------
|
||||||
|
CliXon is a configuration management tool including CLI generation,
|
||||||
|
Yang parser, netconf interface and an embedded databases.
|
||||||
|
|
||||||
Q: How do you build and install Clixon (and the example)?
|
Q: Why should you use CliXon?
|
||||||
A: Clixon: ./configure; make; sudo make install; sudo make install-include
|
-----------------------------
|
||||||
Example: cd example; make; sudo make install
|
If you want an easy-to-use config frontend based on yang with an open-source license.
|
||||||
|
Typically for embedded devices requiring a config interface such as routers and switches.
|
||||||
|
|
||||||
Q: Is there any reference documentation?
|
Q: What license is available?
|
||||||
A: Clixon uses Doxygen for reference documentation.
|
-----------------------------
|
||||||
|
The basic license is open-source, GPLv3. Contact authors for commercial license.
|
||||||
|
|
||||||
|
Q: Is CliXon extendible?
|
||||||
|
------------------------
|
||||||
|
Yes. All application semantics is defined in plugins with well-defined APIs. There are currently three types of plugins: for CLI, for Netconf and for the backend.
|
||||||
|
|
||||||
|
Q: Which language is CliXon implemented in?
|
||||||
|
-------------------------------------------
|
||||||
|
CliXon is written in C. The plugins are written in C. The CLI
|
||||||
|
specification uses cligen.
|
||||||
|
|
||||||
|
There is a project for writing plugins in Python. It is reasonable
|
||||||
|
simple to spawn an external script from a backend.
|
||||||
|
|
||||||
|
Q: Is CliXon different from Clicon?
|
||||||
|
-----------------------------------
|
||||||
|
Yes, but CliXon is a fork of Clicon focussing on Yang specification and XML
|
||||||
|
database. The yang support in clicon was grown out of a key-based
|
||||||
|
scheme that became more and more complex since it had to translate
|
||||||
|
between many different formats. CliXon uses only XML internally.
|
||||||
|
|
||||||
|
The commit transaction mechanism has been simplified too. But CliXon
|
||||||
|
is not backward compliant with key-based Clicon applications, such as
|
||||||
|
Rost.
|
||||||
|
|
||||||
|
Q: How to best understand CliXon?
|
||||||
|
---------------------------------
|
||||||
|
Run the ietf yang routing example. It is used in many of the answers below.
|
||||||
|
|
||||||
|
Q: How do you build and install CliXon (and the example)?
|
||||||
|
---------------------------------------------------------
|
||||||
|
CliXon:
|
||||||
|
./configure;
|
||||||
|
make;
|
||||||
|
sudo make install;
|
||||||
|
sudo make install-include
|
||||||
|
|
||||||
|
The example:
|
||||||
|
cd example;
|
||||||
|
make;
|
||||||
|
sudo make install
|
||||||
|
|
||||||
|
Q: What about reference documentation?
|
||||||
|
--------------------------------------
|
||||||
|
CliXon uses Doxygen for reference documentation.
|
||||||
Build using 'make doc' and aim your browser at doc/html/index.html
|
Build using 'make doc' and aim your browser at doc/html/index.html
|
||||||
|
|
||||||
Q: How do you run the example?
|
Q: How do you run the example?
|
||||||
A: Start a backend server: 'clicon_backend -Ff /usr/local/etc/routing.conf'
|
------------------------------
|
||||||
Start a cli session: clicon_cli -f /usr/local/etc/routing.conf
|
- Start a backend server: 'clicon_backend -Ff /usr/local/etc/routing.conf'
|
||||||
Start a netconf session: clicon_netconf -f /usr/local/etc/routing.conf
|
- Start a cli session: clicon_cli -f /usr/local/etc/routing.conf
|
||||||
|
- Start a netconf session: clicon_netconf -f /usr/local/etc/routing.conf
|
||||||
|
|
||||||
Q: How does Clixon differ from Clicon?
|
Q: How do you change the example?
|
||||||
A: Clixon is a fork of Clicon focussing on Yang specification and XML
|
---------------------------------
|
||||||
database. The yang support in clicon was grown out of a key-based
|
|
||||||
scheme that was complex since it had to translate between
|
|
||||||
formats. Clixon uses only XML. A simplified commit transaction
|
|
||||||
mechanism has been added to. But Clixon is not backward compliant with
|
|
||||||
key-based Clicon applications, such as ROST.
|
|
||||||
|
|
||||||
Q: In the example, how can you alter its semantics?
|
|
||||||
- routing.conf.local - Override default settings
|
- routing.conf.local - Override default settings
|
||||||
- The yang specifications - Alter accepted XML, database format and the configuration part of the CLI commands that are generated.
|
- The yang specifications - This is the central part. It changes the XML, database and the config cli.
|
||||||
- routing_cli.cli - Change the fixed part of the CLI commands
|
- routing_cli.cli - Change the fixed part of the CLI commands
|
||||||
- routing_cli.c - New cli commands may need to write a new C-funtion.
|
- routing_cli.c - Cli C-commands are placed here.
|
||||||
- routing_backend.c - What happens at commit.
|
- routing_backend.c - Commit and validate functions.
|
||||||
- routing_netconf.c - Modify semantics of netconf commands.
|
- routing_netconf.c - Modify semantics of netconf commands.
|
||||||
|
|
||||||
Q: How do you check what is in a database?
|
Q: How do you check what is in a database?
|
||||||
clicon_dbctrl -d <database> -p
|
------------------------------------------
|
||||||
The name of the running or candidate databases are found in the
|
Use clicon_dbctrl. The name of the running or candidate databases are found in the
|
||||||
configuration file, eg /usr/local/var/routing/candidate_db
|
configuration file.
|
||||||
Example:
|
Example:
|
||||||
|
> clicon_dbctrl -d /usr/local/var/routing/candidate_db / -p
|
||||||
/interfaces/interface/eth0/ipv4
|
/interfaces/interface/eth0/ipv4
|
||||||
/interfaces/interface/eth0/type bgp
|
/interfaces/interface/eth0/type bgp
|
||||||
/interfaces/interface/eth0
|
/interfaces/interface/eth0
|
||||||
/interfaces/interface/eth0/name eth0
|
/interfaces/interface/eth0/name eth0
|
||||||
Each line corresponds to a database entry (node in an XML tree). If
|
Each line corresponds to a database entry (node in an XML tree).
|
||||||
the node is a leaf, the value appears as the second entry.
|
If the node is a leaf, the value appears as the second entry ('bgp' and 'eth0').
|
||||||
|
|
||||||
Q: How do you write a commit rule in the example?
|
Q: How do you write a commit function?
|
||||||
A: You write a commit function in routing_backend.c.
|
--------------------------------------
|
||||||
|
You write a commit function in routing_backend.c.
|
||||||
Every time a commit is made, transaction_commit() is called in the
|
Every time a commit is made, transaction_commit() is called in the
|
||||||
backend. It has a 'transaction_data td' argument which is used to fetch
|
backend. It has a 'transaction_data td' argument which is used to fetch
|
||||||
information on added, deleted and changed entries. You access this
|
information on added, deleted and changed entries. You access this
|
||||||
information using access functions as defined in clicon_backend_transaction.h
|
information using access functions as defined in clicon_backend_transaction.h
|
||||||
|
|
||||||
Q: How do you check what has changed on commit?
|
Q: How do you check what has changed on commit?
|
||||||
A: You use XPATHs on the XML trees in the transaction commit callback.
|
-----------------------------------------------
|
||||||
|
You use XPATHs on the XML trees in the transaction commit callback.
|
||||||
Suppose you want to print all added interfaces:
|
Suppose you want to print all added interfaces:
|
||||||
cxobj *target = transaction_target(td); # wanted XML tree
|
cxobj *target = transaction_target(td); # wanted XML tree
|
||||||
# Get all added i/fs
|
vec = xpath_vec_flag(target, "//interface", &len, XML_FLAG_ADD); /* Get added i/fs */
|
||||||
cxobj **vec = xpath_vec_flag(target, "//interface", &len, XML_FLAG_ADD);
|
for (i=0; i<len; i++) /* Loop over added i/fs */
|
||||||
for (i=0; i<len; i++) # Loop over added i/fs
|
clicon_xml2file(stdout, vec[i], 0, 1); /* Print the added interface */
|
||||||
clicon_xml2file(stdout, vec[i]) # Print the added interface
|
You can look for added, deleted and changed entries in this way.
|
||||||
The flags you can check for are: XML_FLAG_ADD, _DEL and _CHANGE, and their combinations.
|
|
||||||
|
|
||||||
Q How do I access the XML tree?
|
Q: How do I access the XML tree?
|
||||||
A: Using XPATH, find and iteration functions defined in the XML library. Example
|
--------------------------------
|
||||||
|
Using XPATH, find and iteration functions defined in the XML library. Example library functions:
|
||||||
|
xml_child_each(),
|
||||||
|
xml_find(),
|
||||||
|
xml_body(),
|
||||||
|
clicon_xml2file(),
|
||||||
|
xml_apply()
|
||||||
|
More are found in the doxygen reference.
|
||||||
|
|
||||||
Q: How do you write a CLI callback function?
|
Q: How do you write a CLI callback function?
|
||||||
You add an entry in routing_cli.cli
|
--------------------------------------------
|
||||||
|
(1) You add an entry in routing_cli.cli
|
||||||
example("This is a comment") <var:int32>("This is a variable"), mycallback("myarg");
|
example("This is a comment") <var:int32>("This is a variable"), mycallback("myarg");
|
||||||
Then define a function in routing_cli.c
|
(2) Then define a function in routing_cli.c
|
||||||
mycallback(clicon_handle h, cvec *cvv, cg_var *arg)
|
mycallback(clicon_handle h, cvec *cvv, cg_var *arg)
|
||||||
where 'cvv' contains the value of the variable and 'arg' contains the
|
where 'cvv' contains the value of the variable and 'arg' contains the
|
||||||
function parameter 'myarg'.
|
function parameter 'myarg'.
|
||||||
|
|
||||||
Q: What are cg_var and cvec used in CLI callbacks?
|
Q: What are cg_var and cvec used in CLI callbacks?
|
||||||
Those are 'CLIgen variables' and vector of CLOgen
|
--------------------------------------------------
|
||||||
variables. Documented in CLIgen documentation. Some examples on usage is found in the
|
Those are 'CLIgen variables' and vector of CLIgen variables.
|
||||||
|
They are documented in CLIgen documentation. Some examples on usage is found in the
|
||||||
routing_cli.c
|
routing_cli.c
|
||||||
|
|
||||||
Q: How do you write a validation rule?
|
Q: How do you write a validation function?
|
||||||
Similar to a commit rule, but instead write the transaction_validate() function.
|
------------------------------------------
|
||||||
Check for consitencies in the XML trees and if they fail, make an clicon_err() call.
|
Similar to a commit function, but instead write the transaction_validate() function.
|
||||||
|
Check for inconsistencies in the XML trees and if they fail, make an clicon_err() call.
|
||||||
clicon_err(OE_PLUGIN, 0, "Route %s lacks ipv4 addr", name);
|
clicon_err(OE_PLUGIN, 0, "Route %s lacks ipv4 addr", name);
|
||||||
return -1;
|
return -1;
|
||||||
The validation or commit will then be aborted.
|
The validation or commit will then be aborted.
|
||||||
|
|
|
||||||
|
|
@ -30,10 +30,10 @@ pdflatex = @PDFLATEX@
|
||||||
|
|
||||||
SUBDIRS =
|
SUBDIRS =
|
||||||
|
|
||||||
.PHONY: clean all $(SUBDIRS)
|
.PHONY: clean all doc $(SUBDIRS)
|
||||||
|
|
||||||
all: $(SUBDIRS) doc
|
all: $(SUBDIRS) doc
|
||||||
echo "Build doxygen doc and graphs: make graphs"
|
echo "Build doxygen doc: make doc"
|
||||||
|
|
||||||
# Regular doxygen documentation
|
# Regular doxygen documentation
|
||||||
doc:
|
doc:
|
||||||
|
|
|
||||||
|
|
@ -40,28 +40,36 @@
|
||||||
/* These include signatures for plugin and transaction callbacks. */
|
/* These include signatures for plugin and transaction callbacks. */
|
||||||
#include <clicon/clicon_backend.h>
|
#include <clicon/clicon_backend.h>
|
||||||
|
|
||||||
/*
|
/*! This is called on validate (and commit). Check validity of candidate
|
||||||
* Commit callback.
|
*/
|
||||||
* We do nothing here but simply create the config based on the current
|
int
|
||||||
* db once everything is done as if will then contain the new config.
|
transaction_validate(clicon_handle h,
|
||||||
|
transaction_data td)
|
||||||
|
{
|
||||||
|
if (debug)
|
||||||
|
transaction_print(stderr, td);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! This is called on commit. Identify modifications and adjust machine state
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
transaction_commit(clicon_handle h,
|
transaction_commit(clicon_handle h,
|
||||||
transaction_data td)
|
transaction_data td)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s\n", __FUNCTION__);
|
cxobj *target = transaction_target(td); /* wanted XML tree */
|
||||||
transaction_print(stderr, td);
|
cxobj **vec;
|
||||||
|
int i;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
/* Get all added i/fs */
|
||||||
|
vec = xpath_vec_flag(target, "//interface", XML_FLAG_ADD, &len);
|
||||||
|
for (i=0; i<len; i++) /* Loop over added i/fs */
|
||||||
|
clicon_xml2file(stdout, vec[i], 0, 1); /* Print the added interface */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
transaction_validate(clicon_handle h,
|
|
||||||
transaction_data td)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "%s\n", __FUNCTION__);
|
|
||||||
transaction_print(stderr, td);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Plugin initialization
|
* Plugin initialization
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,6 @@ cxobj *xml_insert(cxobj *xt, char *tag);
|
||||||
int cxvec_dup(cxobj **vec0, size_t len0, cxobj ***vec1, size_t *len1);
|
int cxvec_dup(cxobj **vec0, size_t len0, cxobj ***vec1, size_t *len1);
|
||||||
int cxvec_append(cxobj *x, cxobj ***vec, size_t *len);
|
int cxvec_append(cxobj *x, cxobj ***vec, size_t *len);
|
||||||
int xml_apply(cxobj *xn, enum cxobj_type type, xml_applyfn_t fn, void *arg);
|
int xml_apply(cxobj *xn, enum cxobj_type type, xml_applyfn_t fn, void *arg);
|
||||||
|
int xml_apply_ancestor(cxobj *xn, xml_applyfn_t fn, void *arg);
|
||||||
|
|
||||||
#endif /* _CLICON_XML_H */
|
#endif /* _CLICON_XML_H */
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,8 @@ int xmlkeyfmt2key2(char *xkfmt, cvec *cvv, char **xk);
|
||||||
int xmlkey2xml(char *xkey, yang_spec *yspec, char **xml);
|
int xmlkey2xml(char *xkey, yang_spec *yspec, char **xml);
|
||||||
int xmldb_get(char *dbname, char *xpath,
|
int xmldb_get(char *dbname, char *xpath,
|
||||||
yang_spec *yspec, cxobj **xtop);
|
yang_spec *yspec, cxobj **xtop);
|
||||||
int xmldb_get_xpath(char *dbname, char *xpath, yang_spec *yspec,
|
int xmldb_get_vec(char *dbname, char *xpath, yang_spec *yspec,
|
||||||
cxobj **xtop, cxobj ***xvec, int *xlen);
|
cxobj **xtop, cxobj ***xvec, size_t *xlen);
|
||||||
int xmldb_put( char *dbname, cxobj *xt,
|
int xmldb_put( char *dbname, cxobj *xt,
|
||||||
yang_spec *yspec, enum operation_type op);
|
yang_spec *yspec, enum operation_type op);
|
||||||
int xmldb_put_xkey(char *dbname, char *xkey, char *val, yang_spec *yspec,
|
int xmldb_put_xkey(char *dbname, char *xkey, char *val, yang_spec *yspec,
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
*/
|
*/
|
||||||
cxobj *xpath_first(cxobj *xn_top, char *xpath);
|
cxobj *xpath_first(cxobj *xn_top, char *xpath);
|
||||||
cxobj *xpath_each(cxobj *xn_top, char *xpath, cxobj *prev);
|
cxobj *xpath_each(cxobj *xn_top, char *xpath, cxobj *prev);
|
||||||
cxobj **xpath_vec(cxobj *xn_top, char *xpath, int *xv_len);
|
cxobj **xpath_vec(cxobj *xn_top, char *xpath, size_t *xv_len);
|
||||||
|
cxobj **xpath_vec_flag(cxobj *cxtop, char *xpath, uint16_t flags, size_t *veclen);
|
||||||
|
|
||||||
#endif /* _CLICON_XSL_H */
|
#endif /* _CLICON_XSL_H */
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@
|
||||||
|
|
||||||
/* clicon */
|
/* clicon */
|
||||||
#include "clicon_err.h"
|
#include "clicon_err.h"
|
||||||
|
#include "clicon_log.h"
|
||||||
#include "clicon_queue.h"
|
#include "clicon_queue.h"
|
||||||
#include "clicon_chunk.h"
|
#include "clicon_chunk.h"
|
||||||
#include "clicon_xml.h"
|
#include "clicon_xml.h"
|
||||||
|
|
@ -998,7 +999,7 @@ cxvec_append(cxobj *x,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Apply a function call recursively on all xml node recursively
|
/*! Apply a function call recursively on all xml node children recursively
|
||||||
* Recursively traverse all xml nodes in a parse-tree and apply fn(arg) for
|
* Recursively traverse all xml nodes in a parse-tree and apply fn(arg) for
|
||||||
* each object found. The function is called with the xml node and an
|
* each object found. The function is called with the xml node and an
|
||||||
* argument as args.
|
* argument as args.
|
||||||
|
|
@ -1037,3 +1038,40 @@ xml_apply(cxobj *xn,
|
||||||
done:
|
done:
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Apply a function call recursively on all ancestors
|
||||||
|
* Recursively traverse upwards to all ancestor nodes in a parse-tree and apply fn(arg) for
|
||||||
|
* each object found. The function is called with the xml node and an
|
||||||
|
* argument as args.
|
||||||
|
* @param[in] xn XML node
|
||||||
|
* @param[in] fn Callback
|
||||||
|
* @param[in] arg Argument
|
||||||
|
* @code
|
||||||
|
* int x_fn(cxobj *x, void *arg)
|
||||||
|
* {
|
||||||
|
* return 0;
|
||||||
|
* }
|
||||||
|
* xml_apply_ancestor(xn, x_fn, NULL);
|
||||||
|
* @endcode
|
||||||
|
* @see xml_apply
|
||||||
|
* @note do not delete or move around any children during this function
|
||||||
|
* @note It does not apply fn to the root node,..
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xml_apply_ancestor(cxobj *xn,
|
||||||
|
xml_applyfn_t fn,
|
||||||
|
void *arg)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cxobj *xp = NULL;
|
||||||
|
|
||||||
|
while ((xp = xml_parent(xn)) != NULL) {
|
||||||
|
if (fn(xp, arg) < 0)
|
||||||
|
goto done;
|
||||||
|
if (xml_apply_ancestor(xp, fn, arg) < 0)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -667,7 +667,7 @@ xmldb_get(char *dbname,
|
||||||
struct db_pair *pairs;
|
struct db_pair *pairs;
|
||||||
cxobj *xt = NULL;
|
cxobj *xt = NULL;
|
||||||
cxobj **xvec=NULL;
|
cxobj **xvec=NULL;
|
||||||
int len;
|
size_t len;
|
||||||
|
|
||||||
/* Read in complete database (this can be optimized) */
|
/* Read in complete database (this can be optimized) */
|
||||||
if ((npairs = db_regexp(dbname, "", __FUNCTION__, &pairs, 0)) < 0)
|
if ((npairs = db_regexp(dbname, "", __FUNCTION__, &pairs, 0)) < 0)
|
||||||
|
|
@ -735,9 +735,9 @@ xmldb_get(char *dbname,
|
||||||
* @code
|
* @code
|
||||||
* cxobj *xt;
|
* cxobj *xt;
|
||||||
* cxobj **xvec;
|
* cxobj **xvec;
|
||||||
* int xlen;
|
* size_t xlen;
|
||||||
* yang_spec *yspec = clicon_dbspec_yang(h);
|
* yang_spec *yspec = clicon_dbspec_yang(h);
|
||||||
* if (xmldb_get_xpath(dbname, "/interfaces/interface[name="eth*"]", yspec,
|
* if (xmldb_get_vec(dbname, "/interfaces/interface[name="eth*"]", yspec,
|
||||||
* &xt, &xvec, &xlen) < 0)
|
* &xt, &xvec, &xlen) < 0)
|
||||||
* err;
|
* err;
|
||||||
* for (i=0; i<xlen; i++){
|
* for (i=0; i<xlen; i++){
|
||||||
|
|
@ -751,12 +751,12 @@ xmldb_get(char *dbname,
|
||||||
* @see xmldb_get
|
* @see xmldb_get
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
xmldb_get_xpath(char *dbname,
|
xmldb_get_vec(char *dbname,
|
||||||
char *xpath,
|
char *xpath,
|
||||||
yang_spec *yspec,
|
yang_spec *yspec,
|
||||||
cxobj **xtop,
|
cxobj **xtop,
|
||||||
cxobj ***xvec,
|
cxobj ***xvec,
|
||||||
int *xlen)
|
size_t *xlen)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
int i;
|
int i;
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@ to the xml standards:
|
||||||
|
|
||||||
/* clicon */
|
/* clicon */
|
||||||
#include "clicon_err.h"
|
#include "clicon_err.h"
|
||||||
|
#include "clicon_log.h"
|
||||||
#include "clicon_xml.h"
|
#include "clicon_xml.h"
|
||||||
#include "clicon_xsl.h"
|
#include "clicon_xsl.h"
|
||||||
|
|
||||||
|
|
@ -304,6 +305,7 @@ static int
|
||||||
recursive_find(cxobj *xn,
|
recursive_find(cxobj *xn,
|
||||||
char *pattern,
|
char *pattern,
|
||||||
int node_type,
|
int node_type,
|
||||||
|
uint16_t flags,
|
||||||
cxobj ***vec0,
|
cxobj ***vec0,
|
||||||
size_t *vec0len)
|
size_t *vec0len)
|
||||||
{
|
{
|
||||||
|
|
@ -315,11 +317,13 @@ recursive_find(cxobj *xn,
|
||||||
xsub = NULL;
|
xsub = NULL;
|
||||||
while ((xsub = xml_child_each(xn, xsub, node_type)) != NULL) {
|
while ((xsub = xml_child_each(xn, xsub, node_type)) != NULL) {
|
||||||
if (fnmatch(pattern, xml_name(xsub), 0) == 0){
|
if (fnmatch(pattern, xml_name(xsub), 0) == 0){
|
||||||
|
clicon_debug(2, "%s %x %x", __FUNCTION__, flags, xml_flag(xsub, flags));
|
||||||
|
if (flags==0x0 || xml_flag(xsub, flags))
|
||||||
if (cxvec_append(xsub, &vec, &veclen) < 0)
|
if (cxvec_append(xsub, &vec, &veclen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
// continue; /* Dont go deeper */
|
// continue; /* Dont go deeper */
|
||||||
}
|
}
|
||||||
if (recursive_find(xsub, pattern, node_type, &vec, &veclen) < 0)
|
if (recursive_find(xsub, pattern, node_type, flags, &vec, &veclen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -331,6 +335,7 @@ recursive_find(cxobj *xn,
|
||||||
|
|
||||||
static int
|
static int
|
||||||
xpath_expr(char *e,
|
xpath_expr(char *e,
|
||||||
|
uint16_t flags,
|
||||||
cxobj ***vec0,
|
cxobj ***vec0,
|
||||||
size_t *vec0len)
|
size_t *vec0len)
|
||||||
{
|
{
|
||||||
|
|
@ -359,18 +364,23 @@ xpath_expr(char *e,
|
||||||
xv = (*vec0)[i];
|
xv = (*vec0)[i];
|
||||||
if ((x = xml_find(xv, e_a)) != NULL &&
|
if ((x = xml_find(xv, e_a)) != NULL &&
|
||||||
(xml_type(x) == CX_ATTR)){
|
(xml_type(x) == CX_ATTR)){
|
||||||
if (!e_v || strcmp(xml_value(x), e_v) == 0)
|
if (!e_v || strcmp(xml_value(x), e_v) == 0){
|
||||||
|
clicon_debug(2, "%s %x %x", __FUNCTION__, flags, xml_flag(xv, flags));
|
||||||
|
if (flags==0x0 || xml_flag(xv, flags))
|
||||||
if (cxvec_append(xv, &vec, &veclen) < 0)
|
if (cxvec_append(xv, &vec, &veclen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else{ /* either <n> or <tag><op><value>, where <op>='=' for now */
|
else{ /* either <n> or <tag><op><value>, where <op>='=' for now */
|
||||||
oplen = strcspn(e, "=");
|
oplen = strcspn(e, "=");
|
||||||
if (strlen(e+oplen)==0){ /* no operator */
|
if (strlen(e+oplen)==0){ /* no operator */
|
||||||
if (sscanf(e, "%d", &i) == 1){ /* number */
|
if (sscanf(e, "%d", &i) == 1){ /* number */
|
||||||
if (i < *vec0len){
|
if (i < *vec0len){
|
||||||
xv = (*vec0)[i]; /* XXX: cant compress: gcc breaks */
|
xv = (*vec0)[i]; /* XXX: cant compress: gcc breaks */
|
||||||
|
clicon_debug(2, "%s %x %x", __FUNCTION__, flags, xml_flag(xv, flags));
|
||||||
|
if (flags==0x0 || xml_flag(xv, flags))
|
||||||
if (cxvec_append(xv, &vec, &veclen) < 0)
|
if (cxvec_append(xv, &vec, &veclen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -393,6 +403,8 @@ xpath_expr(char *e,
|
||||||
(xml_type(x) == CX_ELMNT)){
|
(xml_type(x) == CX_ELMNT)){
|
||||||
if ((val = xml_body(x)) != NULL &&
|
if ((val = xml_body(x)) != NULL &&
|
||||||
strcmp(val, e) == 0){
|
strcmp(val, e) == 0){
|
||||||
|
clicon_debug(2, "%s %x %x", __FUNCTION__, flags, xml_flag(xv, flags));
|
||||||
|
if (flags==0x0 || xml_flag(xv, flags))
|
||||||
if (cxvec_append(xv, &vec, &veclen) < 0)
|
if (cxvec_append(xv, &vec, &veclen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -428,6 +440,7 @@ xpath_find(struct xpath_element *xe,
|
||||||
int descendants0,
|
int descendants0,
|
||||||
cxobj **vec0,
|
cxobj **vec0,
|
||||||
size_t vec0len,
|
size_t vec0len,
|
||||||
|
uint16_t flags,
|
||||||
cxobj ***vec2,
|
cxobj ***vec2,
|
||||||
size_t *vec2len
|
size_t *vec2len
|
||||||
)
|
)
|
||||||
|
|
@ -442,9 +455,11 @@ xpath_find(struct xpath_element *xe,
|
||||||
size_t vec1len = 0;
|
size_t vec1len = 0;
|
||||||
|
|
||||||
if (xe == NULL){
|
if (xe == NULL){
|
||||||
// append
|
/* append */
|
||||||
for (i=0; i<vec0len; i++){
|
for (i=0; i<vec0len; i++){
|
||||||
xv = vec0[i];
|
xv = vec0[i];
|
||||||
|
clicon_debug(2, "%s %x %x", __FUNCTION__, flags, xml_flag(xv, flags));
|
||||||
|
if (flags==0x0 || xml_flag(xv, flags))
|
||||||
cxvec_append(xv, vec2, vec2len);
|
cxvec_append(xv, vec2, vec2len);
|
||||||
}
|
}
|
||||||
free(vec0);
|
free(vec0);
|
||||||
|
|
@ -480,7 +495,7 @@ xpath_find(struct xpath_element *xe,
|
||||||
if (descendants0){
|
if (descendants0){
|
||||||
for (i=0; i<vec0len; i++){
|
for (i=0; i<vec0len; i++){
|
||||||
xv = vec0[i];
|
xv = vec0[i];
|
||||||
if (recursive_find(xv, xe->xe_str, CX_ELMNT, &vec1, &vec1len) < 0)
|
if (recursive_find(xv, xe->xe_str, CX_ELMNT, flags, &vec1, &vec1len) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -490,6 +505,8 @@ xpath_find(struct xpath_element *xe,
|
||||||
x = NULL;
|
x = NULL;
|
||||||
while ((x = xml_child_each(xv, x, -1)) != NULL) {
|
while ((x = xml_child_each(xv, x, -1)) != NULL) {
|
||||||
if (fnmatch(xe->xe_str, xml_name(x), 0) == 0){
|
if (fnmatch(xe->xe_str, xml_name(x), 0) == 0){
|
||||||
|
clicon_debug(2, "%s %x %x", __FUNCTION__, flags, xml_flag(x, flags));
|
||||||
|
if (flags==0x0 || xml_flag(x, flags))
|
||||||
if (cxvec_append(x, &vec1, &vec1len) < 0)
|
if (cxvec_append(x, &vec1, &vec1len) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -517,10 +534,10 @@ xpath_find(struct xpath_element *xe,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (xe->xe_predicate)
|
if (xe->xe_predicate)
|
||||||
if (xpath_expr(xe->xe_predicate, &vec0, &vec0len) < 0)
|
if (xpath_expr(xe->xe_predicate, flags, &vec0, &vec0len) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xpath_find(xe->xe_next, descendants,
|
if (xpath_find(xe->xe_next, descendants,
|
||||||
vec0, vec0len,
|
vec0, vec0len, flags,
|
||||||
vec2, vec2len) < 0)
|
vec2, vec2len) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -574,6 +591,7 @@ static int
|
||||||
xpath_exec(char *xpath,
|
xpath_exec(char *xpath,
|
||||||
cxobj **vec0,
|
cxobj **vec0,
|
||||||
size_t vec0len,
|
size_t vec0len,
|
||||||
|
uint16_t flags,
|
||||||
cxobj ***vec2,
|
cxobj ***vec2,
|
||||||
size_t *vec2len)
|
size_t *vec2len)
|
||||||
{
|
{
|
||||||
|
|
@ -587,7 +605,7 @@ xpath_exec(char *xpath,
|
||||||
goto done;
|
goto done;
|
||||||
if (0)
|
if (0)
|
||||||
xpath_print(stderr, xplist);
|
xpath_print(stderr, xplist);
|
||||||
if (xpath_find(xplist, 0, vec1, vec1len, vec2, vec2len) < 0)
|
if (xpath_find(xplist, 0, vec1, vec1len, flags, vec2, vec2len) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (xpath_free(xplist) < 0)
|
if (xpath_free(xplist) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -607,6 +625,7 @@ xpath_exec(char *xpath,
|
||||||
static int
|
static int
|
||||||
xpath_choice(cxobj *xtop,
|
xpath_choice(cxobj *xtop,
|
||||||
char *xpath0,
|
char *xpath0,
|
||||||
|
uint16_t flags,
|
||||||
cxobj ***vec1,
|
cxobj ***vec1,
|
||||||
size_t *vec1len)
|
size_t *vec1len)
|
||||||
{
|
{
|
||||||
|
|
@ -637,7 +656,7 @@ xpath_choice(cxobj *xtop,
|
||||||
}
|
}
|
||||||
xpath = s1;
|
xpath = s1;
|
||||||
s1 = s2;
|
s1 = s2;
|
||||||
if (xpath_exec(xpath, vec0, vec0len, vec1, vec1len) < 0)
|
if (xpath_exec(xpath, vec0, vec0len, flags, vec1, vec1len) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -667,13 +686,14 @@ xpath_choice(cxobj *xtop,
|
||||||
* @see also xpath_vec.
|
* @see also xpath_vec.
|
||||||
*/
|
*/
|
||||||
cxobj *
|
cxobj *
|
||||||
xpath_first(cxobj *cxtop, char *xpath)
|
xpath_first(cxobj *cxtop,
|
||||||
|
char *xpath)
|
||||||
{
|
{
|
||||||
cxobj **vec0 = NULL;
|
cxobj **vec0 = NULL;
|
||||||
size_t vec0len = 0;
|
size_t vec0len = 0;
|
||||||
cxobj *xn = NULL;
|
cxobj *xn = NULL;
|
||||||
|
|
||||||
if (xpath_choice(cxtop, xpath, &vec0, &vec0len) < 0)
|
if (xpath_choice(cxtop, xpath, 0, &vec0, &vec0len) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
if (vec0len)
|
if (vec0len)
|
||||||
xn = vec0[0];
|
xn = vec0[0];
|
||||||
|
|
@ -707,7 +727,9 @@ xpath_first(cxobj *cxtop, char *xpath)
|
||||||
* NOTE: uses a static variable: consider replacing with xpath_vec() instead
|
* NOTE: uses a static variable: consider replacing with xpath_vec() instead
|
||||||
*/
|
*/
|
||||||
cxobj *
|
cxobj *
|
||||||
xpath_each(cxobj *cxtop, char *xpath, cxobj *xprev)
|
xpath_each(cxobj *cxtop,
|
||||||
|
char *xpath,
|
||||||
|
cxobj *xprev)
|
||||||
{
|
{
|
||||||
static cxobj **vec0 = NULL; /* XXX */
|
static cxobj **vec0 = NULL; /* XXX */
|
||||||
static size_t vec0len = 0;
|
static size_t vec0len = 0;
|
||||||
|
|
@ -718,7 +740,7 @@ xpath_each(cxobj *cxtop, char *xpath, cxobj *xprev)
|
||||||
if (vec0) // XXX
|
if (vec0) // XXX
|
||||||
free(vec0); // XXX
|
free(vec0); // XXX
|
||||||
vec0len = 0;
|
vec0len = 0;
|
||||||
if (xpath_choice(cxtop, xpath, &vec0, &vec0len) < 0)
|
if (xpath_choice(cxtop, xpath, 0, &vec0, &vec0len) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (vec0len){
|
if (vec0len){
|
||||||
|
|
@ -767,12 +789,29 @@ xpath_each(cxobj *cxtop, char *xpath, cxobj *xprev)
|
||||||
cxobj **
|
cxobj **
|
||||||
xpath_vec(cxobj *cxtop,
|
xpath_vec(cxobj *cxtop,
|
||||||
char *xpath,
|
char *xpath,
|
||||||
int *veclen)
|
size_t *veclen)
|
||||||
{
|
{
|
||||||
cxobj **vec=NULL;
|
cxobj **vec=NULL;
|
||||||
|
|
||||||
*veclen = 0;
|
*veclen = 0;
|
||||||
if (xpath_choice(cxtop, xpath, &vec, (size_t*)veclen) < 0)
|
if (xpath_choice(cxtop, xpath, 0, &vec, (size_t*)veclen) < 0)
|
||||||
|
return NULL;
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A restricted xpath that returns a vector of matches (only nodes marked with flags)
|
||||||
|
* @param[in] flags Set of flags that return nodes must match (0 if all)
|
||||||
|
*/
|
||||||
|
cxobj **
|
||||||
|
xpath_vec_flag(cxobj *cxtop,
|
||||||
|
char *xpath,
|
||||||
|
uint16_t flags,
|
||||||
|
size_t *veclen)
|
||||||
|
{
|
||||||
|
cxobj **vec=NULL;
|
||||||
|
|
||||||
|
*veclen = 0;
|
||||||
|
if (xpath_choice(cxtop, xpath, flags, &vec, (size_t*)veclen) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
return vec;
|
return vec;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue