* Full support of XPATH 1.0 according to https://www.w3.org/TR/xpath-10 using yacc/lex
* The previous XPATH imlementation was very restricted. * The only function implemented is the Yang extension "current()". No other functions are implemented (eg last(), count()).
This commit is contained in:
parent
60ce7b12bd
commit
bf728b37b8
26 changed files with 2856 additions and 481 deletions
|
|
@ -2,6 +2,9 @@
|
||||||
|
|
||||||
## 3.7.0 (Upcoming)
|
## 3.7.0 (Upcoming)
|
||||||
### Major changes:
|
### Major changes:
|
||||||
|
* Full support of XPATH 1.0 according to https://www.w3.org/TR/xpath-10 using yacc/lex
|
||||||
|
* The previous XPATH imlementation was very restricted.
|
||||||
|
* The only function implemented is the Yang extension "current()". No other functions are implemented (eg last(), count()).
|
||||||
* Support for YANG identity and identityref according to RFC 7950 Sec 7.18 and 9.10
|
* Support for YANG identity and identityref according to RFC 7950 Sec 7.18 and 9.10
|
||||||
* Previous support did no validation of values.
|
* Previous support did no validation of values.
|
||||||
* Validation of types and CLI expansion
|
* Validation of types and CLI expansion
|
||||||
|
|
@ -9,7 +12,7 @@
|
||||||
* Applications which have not strictly enforced the identities may now have problems with validation and may need to be modified.
|
* Applications which have not strictly enforced the identities may now have problems with validation and may need to be modified.
|
||||||
|
|
||||||
### Minor changes:
|
### Minor changes:
|
||||||
* Dedicated xml,json,yang and xsl parser utility programs added
|
* Dedicated xml,json,yang and xpath parser utility programs added
|
||||||
* CDATA xml support (patch by David Cornejo, Netgate)
|
* CDATA xml support (patch by David Cornejo, Netgate)
|
||||||
* Encode and decode (parsing) support
|
* Encode and decode (parsing) support
|
||||||
* Validation of yang bits type space-separated list value
|
* Validation of yang bits type space-separated list value
|
||||||
|
|
@ -47,7 +50,7 @@
|
||||||
* See FAQ and example
|
* See FAQ and example
|
||||||
|
|
||||||
### Corrected Bugs
|
### Corrected Bugs
|
||||||
* Prefix of rpc was ignored
|
* Prefix of rpc was ignored (thanks Dmitri at netgate)
|
||||||
* https://github.com/clicon/clixon/issues/30
|
* https://github.com/clicon/clixon/issues/30
|
||||||
* Added cli returna value also for single commands (eg -1)
|
* Added cli returna value also for single commands (eg -1)
|
||||||
* Fixed JSON unbalanced braces resulting in assert.
|
* Fixed JSON unbalanced braces resulting in assert.
|
||||||
|
|
|
||||||
|
|
@ -457,7 +457,7 @@ main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cli_syntax_mode(h)){
|
if (!cli_syntax_mode(h)){
|
||||||
fprintf (stderr, "FATAL: No cli mode set (use -m or CLICON_CLI_MODE)\n");
|
fprintf(stderr, "FATAL: No cli mode set (use -m or CLICON_CLI_MODE)\n");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (cligen_tree_find(cli_cligen(h), cli_syntax_mode(h)) == NULL)
|
if (cligen_tree_find(cli_cligen(h), cli_syntax_mode(h)) == NULL)
|
||||||
|
|
|
||||||
|
|
@ -97,7 +97,7 @@ syntax_mode_find(cli_syntax_t *stx,
|
||||||
perror("malloc");
|
perror("malloc");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
memset (m, 0, sizeof (*m));
|
memset(m, 0, sizeof(*m));
|
||||||
strncpy(m->csm_name, mode, sizeof(m->csm_name)-1);
|
strncpy(m->csm_name, mode, sizeof(m->csm_name)-1);
|
||||||
strncpy(m->csm_prompt, CLI_DEFAULT_PROMPT, sizeof(m->csm_prompt)-1);
|
strncpy(m->csm_prompt, CLI_DEFAULT_PROMPT, sizeof(m->csm_prompt)-1);
|
||||||
INSQ(m, stx->stx_modes);
|
INSQ(m, stx->stx_modes);
|
||||||
|
|
@ -314,7 +314,7 @@ done:
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
cli_syntax_load (clicon_handle h)
|
cli_syntax_load(clicon_handle h)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *plugin_dir = NULL;
|
char *plugin_dir = NULL;
|
||||||
|
|
@ -343,7 +343,7 @@ cli_syntax_load (clicon_handle h)
|
||||||
clicon_err(OE_UNIX, errno, "malloc");
|
clicon_err(OE_UNIX, errno, "malloc");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
memset (stx, 0, sizeof (*stx)); /* Zero out all */
|
memset(stx, 0, sizeof(*stx)); /* Zero out all */
|
||||||
|
|
||||||
cli_syntax_set(h, stx);
|
cli_syntax_set(h, stx);
|
||||||
|
|
||||||
|
|
@ -676,7 +676,7 @@ cli_set_prompt(clicon_handle h,
|
||||||
* @param[in] fmt Stdarg fmt string
|
* @param[in] fmt Stdarg fmt string
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
prompt_fmt (char *prompt,
|
prompt_fmt(char *prompt,
|
||||||
size_t plen,
|
size_t plen,
|
||||||
char *fmt, ...)
|
char *fmt, ...)
|
||||||
{
|
{
|
||||||
|
|
@ -698,7 +698,7 @@ prompt_fmt (char *prompt,
|
||||||
if (*s == '%' && *++s) {
|
if (*s == '%' && *++s) {
|
||||||
switch(*s) {
|
switch(*s) {
|
||||||
case 'H': /* Hostname */
|
case 'H': /* Hostname */
|
||||||
if (gethostname (hname, sizeof (hname)) != 0)
|
if (gethostname(hname, sizeof(hname)) != 0)
|
||||||
strncpy(hname, "unknown", sizeof(hname)-1);
|
strncpy(hname, "unknown", sizeof(hname)-1);
|
||||||
cprintf(cb, "%s", hname);
|
cprintf(cb, "%s", hname);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ chunk_initialize ()
|
||||||
|
|
||||||
chunk_pagesz = getpagesize();
|
chunk_pagesz = getpagesize();
|
||||||
|
|
||||||
bzero (&chunk_heads, sizeof (chunk_heads));
|
bzero (&chunk_heads, sizeof(chunk_heads));
|
||||||
|
|
||||||
for (idx = 0; idx < CHUNK_HEADS; idx++) {
|
for (idx = 0; idx < CHUNK_HEADS; idx++) {
|
||||||
chunk_head_t *chead = &chunk_heads[idx];
|
chunk_head_t *chead = &chunk_heads[idx];
|
||||||
|
|
@ -121,7 +121,7 @@ chunk_initialize ()
|
||||||
*/
|
*/
|
||||||
chead->ch_size =
|
chead->ch_size =
|
||||||
(chead->ch_blksz / chead->ch_nchkperblk)
|
(chead->ch_blksz / chead->ch_nchkperblk)
|
||||||
- sizeof (chunk_t);
|
- sizeof(chunk_t);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,22 +150,22 @@ chunk_new_block (chunk_head_t *chead)
|
||||||
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||||
if (blk == MAP_FAILED)
|
if (blk == MAP_FAILED)
|
||||||
return -1;
|
return -1;
|
||||||
memset ((void *)blk, 0, sizeof(*blk));
|
memset((void *)blk, 0, sizeof(*blk));
|
||||||
|
|
||||||
/* Allocate chunk block */
|
/* Allocate chunk block */
|
||||||
blk->cb_blk = (void *)
|
blk->cb_blk = (void *)
|
||||||
mmap(NULL, chead->ch_blksz,
|
mmap(NULL, chead->ch_blksz,
|
||||||
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||||
if (blk->cb_blk == MAP_FAILED) {
|
if (blk->cb_blk == MAP_FAILED) {
|
||||||
munmap (blk, chead->ch_blksz);
|
munmap(blk, chead->ch_blksz);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
memset (blk->cb_blk, 0, chead->ch_blksz);
|
memset(blk->cb_blk, 0, chead->ch_blksz);
|
||||||
|
|
||||||
|
|
||||||
/* Initialize chunk header */
|
/* Initialize chunk header */
|
||||||
blk->cb_head = chead;
|
blk->cb_head = chead;
|
||||||
INSQ (blk, chead->ch_blks);
|
INSQ(blk, chead->ch_blks);
|
||||||
chead->ch_nblks++;
|
chead->ch_nblks++;
|
||||||
|
|
||||||
/* Initialize chunks */
|
/* Initialize chunks */
|
||||||
|
|
@ -174,10 +174,10 @@ chunk_new_block (chunk_head_t *chead)
|
||||||
|
|
||||||
cnk = (chunk_t *)c;
|
cnk = (chunk_t *)c;
|
||||||
cnk->c_blk = blk;
|
cnk->c_blk = blk;
|
||||||
INSQ (cnk, chead->ch_free);
|
INSQ(cnk, chead->ch_free);
|
||||||
chead->ch_nfree++;
|
chead->ch_nfree++;
|
||||||
|
|
||||||
c += (chead->ch_size + sizeof (chunk_t));
|
c += (chead->ch_size + sizeof(chunk_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -188,7 +188,7 @@ chunk_new_block (chunk_head_t *chead)
|
||||||
* chunk_release_block() - Unqueue a block, it's chunks and free mem
|
* chunk_release_block() - Unqueue a block, it's chunks and free mem
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
chunk_release_block (chunk_block_t *cblk)
|
chunk_release_block(chunk_block_t *cblk)
|
||||||
{
|
{
|
||||||
int idx;
|
int idx;
|
||||||
char *c;
|
char *c;
|
||||||
|
|
@ -201,7 +201,7 @@ chunk_release_block (chunk_block_t *cblk)
|
||||||
/*
|
/*
|
||||||
* Dequeue block
|
* Dequeue block
|
||||||
*/
|
*/
|
||||||
DELQ (cblk, chead->ch_blks, chunk_block_t *);
|
DELQ(cblk, chead->ch_blks, chunk_block_t *);
|
||||||
chead->ch_nblks--;
|
chead->ch_nblks--;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -211,17 +211,17 @@ chunk_release_block (chunk_block_t *cblk)
|
||||||
for (idx = 0; idx < chead->ch_nchkperblk; idx++) {
|
for (idx = 0; idx < chead->ch_nchkperblk; idx++) {
|
||||||
|
|
||||||
cnk = (chunk_t *)c;
|
cnk = (chunk_t *)c;
|
||||||
DELQ (cnk, chead->ch_free, chunk_t *);
|
DELQ(cnk, chead->ch_free, chunk_t *);
|
||||||
chead->ch_nfree--;
|
chead->ch_nfree--;
|
||||||
|
|
||||||
c += (chead->ch_size + sizeof (chunk_t));
|
c += (chead->ch_size + sizeof(chunk_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free block
|
* Free block
|
||||||
*/
|
*/
|
||||||
munmap ((void *)cblk->cb_blk, chead->ch_blksz);
|
munmap((void *)cblk->cb_blk, chead->ch_blksz);
|
||||||
munmap ((void *)cblk, sizeof(*cblk));
|
munmap((void *)cblk, sizeof(*cblk));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -230,7 +230,7 @@ chunk_release_block (chunk_block_t *cblk)
|
||||||
* chunk_alloc() - Map new chunk of memory
|
* chunk_alloc() - Map new chunk of memory
|
||||||
*/
|
*/
|
||||||
static void *
|
static void *
|
||||||
chunk_alloc (size_t len)
|
chunk_alloc(size_t len)
|
||||||
{
|
{
|
||||||
register int idx;
|
register int idx;
|
||||||
chunk_head_t *chead;
|
chunk_head_t *chead;
|
||||||
|
|
@ -258,21 +258,21 @@ chunk_alloc (size_t len)
|
||||||
|
|
||||||
/* Get new block if necessary */
|
/* Get new block if necessary */
|
||||||
if (!chead->ch_nfree)
|
if (!chead->ch_nfree)
|
||||||
if (chunk_new_block (chead))
|
if (chunk_new_block(chead))
|
||||||
return (void *)NULL;
|
return (void *)NULL;
|
||||||
|
|
||||||
|
|
||||||
/* Move a free chunk to the in-use list */
|
/* Move a free chunk to the in-use list */
|
||||||
cnk = chead->ch_free;
|
cnk = chead->ch_free;
|
||||||
DELQ (cnk, chead->ch_free, chunk_t *);
|
DELQ(cnk, chead->ch_free, chunk_t *);
|
||||||
chead->ch_nfree--;
|
chead->ch_nfree--;
|
||||||
INSQ (cnk, chead->ch_cnks);
|
INSQ(cnk, chead->ch_cnks);
|
||||||
/* Add reference to the corresponding block */
|
/* Add reference to the corresponding block */
|
||||||
cnk->c_blk->cb_ref++;
|
cnk->c_blk->cb_ref++;
|
||||||
|
|
||||||
#ifdef CHUNK_DIAG
|
#ifdef CHUNK_DIAG
|
||||||
/* Clear diag info */
|
/* Clear diag info */
|
||||||
bzero ((void *)&cnk->c_diag, sizeof (cnk->c_diag));
|
bzero((void *)&cnk->c_diag, sizeof(cnk->c_diag));
|
||||||
#endif /* CHUNK_DIAG */
|
#endif /* CHUNK_DIAG */
|
||||||
|
|
||||||
/* Return pointer to first byte after the chunk header */
|
/* Return pointer to first byte after the chunk header */
|
||||||
|
|
@ -285,9 +285,9 @@ chunk_alloc (size_t len)
|
||||||
*/
|
*/
|
||||||
void *
|
void *
|
||||||
#ifdef CHUNK_DIAG
|
#ifdef CHUNK_DIAG
|
||||||
_chunk (size_t len, const char *name, const char *file, int line)
|
_chunk(size_t len, const char *name, const char *file, int line)
|
||||||
#else
|
#else
|
||||||
chunk (size_t len, const char *name)
|
chunk(size_t len, const char *name)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
int newgrp = 0;
|
int newgrp = 0;
|
||||||
|
|
@ -306,10 +306,10 @@ chunk (size_t len, const char *name)
|
||||||
|
|
||||||
/* Get actual chunk
|
/* Get actual chunk
|
||||||
*/
|
*/
|
||||||
ptr = chunk_alloc (len);
|
ptr = chunk_alloc(len);
|
||||||
if (!ptr)
|
if (!ptr)
|
||||||
goto error;
|
goto error;
|
||||||
cnk = (chunk_t *) (((char *)ptr) - sizeof (chunk_t));
|
cnk = (chunk_t *) (((char *)ptr) - sizeof(chunk_t));
|
||||||
|
|
||||||
#ifdef CHUNK_DIAG
|
#ifdef CHUNK_DIAG
|
||||||
/* Store who reuested us
|
/* Store who reuested us
|
||||||
|
|
@ -329,7 +329,7 @@ chunk (size_t len, const char *name)
|
||||||
if (chunk_grp) {
|
if (chunk_grp) {
|
||||||
tmp = chunk_grp;
|
tmp = chunk_grp;
|
||||||
do {
|
do {
|
||||||
if (!strcmp (tmp->cg_name, name)) {
|
if (!strcmp(tmp->cg_name, name)) {
|
||||||
grp = tmp;
|
grp = tmp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -343,26 +343,26 @@ chunk (size_t len, const char *name)
|
||||||
*/
|
*/
|
||||||
if ( !grp ) {
|
if ( !grp ) {
|
||||||
|
|
||||||
grp = (chunk_group_t *) chunk_alloc (sizeof (chunk_group_t));
|
grp = (chunk_group_t *) chunk_alloc(sizeof(chunk_group_t));
|
||||||
if (!grp)
|
if (!grp)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
bzero (grp, sizeof (chunk_group_t));
|
bzero(grp, sizeof(chunk_group_t));
|
||||||
|
|
||||||
grp->cg_name = (char *) chunk_alloc (strlen (name) + 1);
|
grp->cg_name = (char *) chunk_alloc(strlen(name) + 1);
|
||||||
if (!grp->cg_name)
|
if (!grp->cg_name)
|
||||||
goto error;
|
goto error;
|
||||||
bcopy (name, grp->cg_name, strlen(name)+1);
|
bcopy(name, grp->cg_name, strlen(name)+1);
|
||||||
newgrp = 1;
|
newgrp = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Get new entry.
|
/* Get new entry.
|
||||||
*/
|
*/
|
||||||
ent = (chunk_grpent_t *) chunk_alloc (sizeof (chunk_grpent_t));
|
ent = (chunk_grpent_t *) chunk_alloc(sizeof(chunk_grpent_t));
|
||||||
if (!ent)
|
if (!ent)
|
||||||
goto error;
|
goto error;
|
||||||
bzero (ent, sizeof (chunk_grpent_t));
|
bzero(ent, sizeof(chunk_grpent_t));
|
||||||
|
|
||||||
/* Now put everything together
|
/* Now put everything together
|
||||||
*/
|
*/
|
||||||
|
|
@ -371,22 +371,22 @@ chunk (size_t len, const char *name)
|
||||||
ent->ce_cnk = cnk;
|
ent->ce_cnk = cnk;
|
||||||
ent->ce_grp = grp;
|
ent->ce_grp = grp;
|
||||||
|
|
||||||
INSQ (ent, grp->cg_ent);
|
INSQ(ent, grp->cg_ent);
|
||||||
if (newgrp)
|
if (newgrp)
|
||||||
INSQ (grp, chunk_grp);
|
INSQ(grp, chunk_grp);
|
||||||
|
|
||||||
return (ptr);
|
return (ptr);
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (grp && newgrp) {
|
if (grp && newgrp) {
|
||||||
if (grp->cg_name)
|
if (grp->cg_name)
|
||||||
unchunk (grp->cg_name);
|
unchunk(grp->cg_name);
|
||||||
unchunk (grp);
|
unchunk(grp);
|
||||||
}
|
}
|
||||||
if (ent)
|
if (ent)
|
||||||
unchunk (ent);
|
unchunk(ent);
|
||||||
if (ptr)
|
if (ptr)
|
||||||
unchunk (ptr);
|
unchunk(ptr);
|
||||||
|
|
||||||
return (void *) NULL;
|
return (void *) NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -397,9 +397,9 @@ chunk (size_t len, const char *name)
|
||||||
*/
|
*/
|
||||||
void *
|
void *
|
||||||
#ifdef CHUNK_DIAG
|
#ifdef CHUNK_DIAG
|
||||||
_rechunk (void *ptr, size_t len, const char *name, const char *file, int line)
|
_rechunk(void *ptr, size_t len, const char *name, const char *file, int line)
|
||||||
#else
|
#else
|
||||||
rechunk (void *ptr, size_t len, const char *name)
|
rechunk(void *ptr, size_t len, const char *name)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
int idx;
|
int idx;
|
||||||
|
|
@ -414,22 +414,22 @@ rechunk (void *ptr, size_t len, const char *name)
|
||||||
*/
|
*/
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
#ifdef CHUNK_DIAG
|
#ifdef CHUNK_DIAG
|
||||||
return _chunk (len, name, file, line);
|
return _chunk(len, name, file, line);
|
||||||
#else
|
#else
|
||||||
return chunk (len, name);
|
return chunk(len, name);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Zero length, free chunk
|
/* Zero length, free chunk
|
||||||
*/
|
*/
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
unchunk (ptr);
|
unchunk(ptr);
|
||||||
return (void *) NULL;
|
return (void *) NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Rewind pointer to beginning of chunk header
|
/* Rewind pointer to beginning of chunk header
|
||||||
*/
|
*/
|
||||||
cnk = (chunk_t *) (((char *)ptr) - sizeof (chunk_t));
|
cnk = (chunk_t *) (((char *)ptr) - sizeof(chunk_t));
|
||||||
chead = cnk->c_blk->cb_head;
|
chead = cnk->c_blk->cb_head;
|
||||||
|
|
||||||
/* Find sufficient sized block head
|
/* Find sufficient sized block head
|
||||||
|
|
@ -451,22 +451,22 @@ rechunk (void *ptr, size_t len, const char *name)
|
||||||
/* Get new chunk
|
/* Get new chunk
|
||||||
*/
|
*/
|
||||||
#ifdef CHUNK_DIAG
|
#ifdef CHUNK_DIAG
|
||||||
new = _chunk (len, name, file, line);
|
new = _chunk(len, name, file, line);
|
||||||
#else
|
#else
|
||||||
new = chunk (len, name);
|
new = chunk(len, name);
|
||||||
#endif
|
#endif
|
||||||
if (!new)
|
if (!new)
|
||||||
return (void *) NULL;
|
return (void *) NULL;
|
||||||
newcnk = (chunk_t *) (((char *)new) - sizeof (chunk_t));
|
newcnk = (chunk_t *) (((char *)new) - sizeof(chunk_t));
|
||||||
newchead = newcnk->c_blk->cb_head;
|
newchead = newcnk->c_blk->cb_head;
|
||||||
|
|
||||||
/* Copy contents to new chunk
|
/* Copy contents to new chunk
|
||||||
*/
|
*/
|
||||||
bcopy (ptr, new, MIN(newchead->ch_size, chead->ch_size));
|
bcopy(ptr, new, MIN(newchead->ch_size, chead->ch_size));
|
||||||
|
|
||||||
/* Free old chunk
|
/* Free old chunk
|
||||||
*/
|
*/
|
||||||
unchunk (ptr);
|
unchunk(ptr);
|
||||||
|
|
||||||
|
|
||||||
return (new);
|
return (new);
|
||||||
|
|
@ -476,7 +476,7 @@ rechunk (void *ptr, size_t len, const char *name)
|
||||||
* unchunk() - Release chunk
|
* unchunk() - Release chunk
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
unchunk (void *ptr)
|
unchunk(void *ptr)
|
||||||
{
|
{
|
||||||
chunk_t *cnk;
|
chunk_t *cnk;
|
||||||
chunk_head_t *chead;
|
chunk_head_t *chead;
|
||||||
|
|
@ -489,14 +489,14 @@ unchunk (void *ptr)
|
||||||
|
|
||||||
/* Rewind pointer to beginning of chunk header
|
/* Rewind pointer to beginning of chunk header
|
||||||
*/
|
*/
|
||||||
cnk = (chunk_t *) (((char *)ptr) - sizeof (chunk_t));
|
cnk = (chunk_t *) (((char *)ptr) - sizeof(chunk_t));
|
||||||
cblk = cnk->c_blk;
|
cblk = cnk->c_blk;
|
||||||
chead = cblk->cb_head;
|
chead = cblk->cb_head;
|
||||||
|
|
||||||
/* Move chunk back to free list
|
/* Move chunk back to free list
|
||||||
*/
|
*/
|
||||||
DELQ (cnk, chead->ch_cnks, chunk_t *);
|
DELQ(cnk, chead->ch_cnks, chunk_t *);
|
||||||
INSQ (cnk, chead->ch_free);
|
INSQ(cnk, chead->ch_free);
|
||||||
chead->ch_nfree++;
|
chead->ch_nfree++;
|
||||||
|
|
||||||
/* If chunk is grouped, remove from group.
|
/* If chunk is grouped, remove from group.
|
||||||
|
|
@ -504,13 +504,13 @@ unchunk (void *ptr)
|
||||||
ent = cnk->c_grpent;
|
ent = cnk->c_grpent;
|
||||||
if (ent) {
|
if (ent) {
|
||||||
grp = ent->ce_grp;
|
grp = ent->ce_grp;
|
||||||
DELQ (ent, grp->cg_ent, chunk_grpent_t *);
|
DELQ(ent, grp->cg_ent, chunk_grpent_t *);
|
||||||
unchunk (ent);
|
unchunk(ent);
|
||||||
cnk->c_grpent = NULL;
|
cnk->c_grpent = NULL;
|
||||||
|
|
||||||
/* Group empty? */
|
/* Group empty? */
|
||||||
if (!dont_unchunk_group && !grp->cg_ent) {
|
if (!dont_unchunk_group && !grp->cg_ent) {
|
||||||
DELQ (grp, chunk_grp, chunk_group_t *);
|
DELQ(grp, chunk_grp, chunk_group_t *);
|
||||||
unchunk(grp->cg_name);
|
unchunk(grp->cg_name);
|
||||||
unchunk(grp);
|
unchunk(grp);
|
||||||
}
|
}
|
||||||
|
|
@ -528,7 +528,7 @@ unchunk (void *ptr)
|
||||||
* unchunk_group() - Release all group chunks.
|
* unchunk_group() - Release all group chunks.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
unchunk_group (const char *name)
|
unchunk_group(const char *name)
|
||||||
{
|
{
|
||||||
chunk_group_t *tmp;
|
chunk_group_t *tmp;
|
||||||
chunk_group_t *grp = NULL;
|
chunk_group_t *grp = NULL;
|
||||||
|
|
@ -542,7 +542,7 @@ unchunk_group (const char *name)
|
||||||
if (chunk_grp) {
|
if (chunk_grp) {
|
||||||
tmp = chunk_grp;
|
tmp = chunk_grp;
|
||||||
do {
|
do {
|
||||||
if (!strcmp (tmp->cg_name, name)) {
|
if (!strcmp(tmp->cg_name, name)) {
|
||||||
grp = tmp;
|
grp = tmp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -560,16 +560,16 @@ unchunk_group (const char *name)
|
||||||
dont_unchunk_group = 1;
|
dont_unchunk_group = 1;
|
||||||
while (grp->cg_ent) {
|
while (grp->cg_ent) {
|
||||||
cnk = grp->cg_ent->ce_cnk;
|
cnk = grp->cg_ent->ce_cnk;
|
||||||
unchunk ((chunk_t *)(((char *)cnk) + sizeof (chunk_t)));
|
unchunk((chunk_t *)(((char *)cnk) + sizeof(chunk_t)));
|
||||||
}
|
}
|
||||||
dont_unchunk_group = 0;
|
dont_unchunk_group = 0;
|
||||||
|
|
||||||
|
|
||||||
/* Remove group from list and free it
|
/* Remove group from list and free it
|
||||||
*/
|
*/
|
||||||
DELQ (grp, chunk_grp, chunk_group_t *);
|
DELQ(grp, chunk_grp, chunk_group_t *);
|
||||||
unchunk (grp->cg_name);
|
unchunk(grp->cg_name);
|
||||||
unchunk (grp);
|
unchunk(grp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -577,9 +577,9 @@ unchunk_group (const char *name)
|
||||||
*/
|
*/
|
||||||
void *
|
void *
|
||||||
#ifdef CHUNK_DIAG
|
#ifdef CHUNK_DIAG
|
||||||
_chunkdup (const void *ptr, size_t len, const char *name, const char *file, int line)
|
_chunkdup(const void *ptr, size_t len, const char *name, const char *file, int line)
|
||||||
#else
|
#else
|
||||||
chunkdup (const void *ptr, size_t len, const char *name)
|
chunkdup(const void *ptr, size_t len, const char *name)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
void *new;
|
void *new;
|
||||||
|
|
@ -592,9 +592,9 @@ chunkdup (const void *ptr, size_t len, const char *name)
|
||||||
/* Get new chunk
|
/* Get new chunk
|
||||||
*/
|
*/
|
||||||
#ifdef CHUNK_DIAG
|
#ifdef CHUNK_DIAG
|
||||||
new = _chunk (len, name, file, line);
|
new = _chunk(len, name, file, line);
|
||||||
#else
|
#else
|
||||||
new = chunk (len, name);
|
new = chunk(len, name);
|
||||||
#endif
|
#endif
|
||||||
if (!new)
|
if (!new)
|
||||||
return (void *)NULL;
|
return (void *)NULL;
|
||||||
|
|
@ -610,7 +610,7 @@ chunkdup (const void *ptr, size_t len, const char *name)
|
||||||
* chunksize() - Return size of memory chunk.
|
* chunksize() - Return size of memory chunk.
|
||||||
*/
|
*/
|
||||||
size_t
|
size_t
|
||||||
chunksize (void *ptr)
|
chunksize(void *ptr)
|
||||||
{
|
{
|
||||||
chunk_t *cnk;
|
chunk_t *cnk;
|
||||||
chunk_head_t *chead;
|
chunk_head_t *chead;
|
||||||
|
|
@ -621,7 +621,7 @@ chunksize (void *ptr)
|
||||||
|
|
||||||
/* Rewind pointer to beginning of chunk header
|
/* Rewind pointer to beginning of chunk header
|
||||||
*/
|
*/
|
||||||
cnk = (chunk_t *) (((char *)ptr) - sizeof (chunk_t));
|
cnk = (chunk_t *) (((char *)ptr) - sizeof(chunk_t));
|
||||||
cblk = cnk->c_blk;
|
cblk = cnk->c_blk;
|
||||||
chead = cblk->cb_head;
|
chead = cblk->cb_head;
|
||||||
|
|
||||||
|
|
@ -635,10 +635,10 @@ chunksize (void *ptr)
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
#ifdef CHUNK_DIAG
|
#ifdef CHUNK_DIAG
|
||||||
_chunk_strncat (const char *dst, const char *src, size_t n, const char *name,
|
_chunk_strncat(const char *dst, const char *src, size_t n, const char *name,
|
||||||
const char *file, int line)
|
const char *file, int line)
|
||||||
#else
|
#else
|
||||||
chunk_strncat (const char *dst, const char *src, size_t n, const char *name)
|
chunk_strncat(const char *dst, const char *src, size_t n, const char *name)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
@ -651,7 +651,7 @@ chunk_strncat (const char *dst, const char *src, size_t n, const char *name)
|
||||||
#ifdef CHUNK_DIAG
|
#ifdef CHUNK_DIAG
|
||||||
ptr = _rechunk(ptr, len, name, file, line);
|
ptr = _rechunk(ptr, len, name, file, line);
|
||||||
#else
|
#else
|
||||||
ptr = rechunk (ptr, len, name);
|
ptr = rechunk(ptr, len, name);
|
||||||
#endif
|
#endif
|
||||||
if (ptr == NULL)
|
if (ptr == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -670,10 +670,10 @@ chunk_strncat (const char *dst, const char *src, size_t n, const char *name)
|
||||||
*/
|
*/
|
||||||
char *
|
char *
|
||||||
#ifdef CHUNK_DIAG
|
#ifdef CHUNK_DIAG
|
||||||
_chunk_sprintf (const char *name, const char *file,
|
_chunk_sprintf(const char *name, const char *file,
|
||||||
int line, const char *fmt, ...)
|
int line, const char *fmt, ...)
|
||||||
#else
|
#else
|
||||||
chunk_sprintf (const char *name, char *fmt, ...)
|
chunk_sprintf(const char *name, char *fmt, ...)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
@ -683,13 +683,13 @@ chunk_sprintf (const char *name, char *fmt, ...)
|
||||||
/* Calculate formatted string length */
|
/* Calculate formatted string length */
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
len = vsnprintf(NULL, 0, fmt, args) + 1;
|
len = vsnprintf(NULL, 0, fmt, args) + 1;
|
||||||
va_end (args);
|
va_end(args);
|
||||||
|
|
||||||
/* get chunk */
|
/* get chunk */
|
||||||
#ifdef CHUNK_DIAG
|
#ifdef CHUNK_DIAG
|
||||||
str = _chunk (len, name, file, line);
|
str = _chunk(len, name, file, line);
|
||||||
#else
|
#else
|
||||||
str = chunk (len, name);
|
str = chunk(len, name);
|
||||||
#endif
|
#endif
|
||||||
if (str == NULL)
|
if (str == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -697,7 +697,7 @@ chunk_sprintf (const char *name, char *fmt, ...)
|
||||||
/* Format string */
|
/* Format string */
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
len = vsnprintf(str, len, fmt, args);
|
len = vsnprintf(str, len, fmt, args);
|
||||||
va_end (args);
|
va_end(args);
|
||||||
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
@ -756,7 +756,7 @@ chunk_check(FILE *fout, const char *name)
|
||||||
if (chunk_grp) {
|
if (chunk_grp) {
|
||||||
tmp = chunk_grp;
|
tmp = chunk_grp;
|
||||||
do {
|
do {
|
||||||
if (!strcmp (tmp->cg_name, name)) {
|
if (!strcmp(tmp->cg_name, name)) {
|
||||||
grp = tmp;
|
grp = tmp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -436,7 +436,7 @@ db_regexp(char *file,
|
||||||
goto quit;
|
goto quit;
|
||||||
}
|
}
|
||||||
pair = &newpairs[npairs];
|
pair = &newpairs[npairs];
|
||||||
memset (pair, 0, sizeof(*pair));
|
memset(pair, 0, sizeof(*pair));
|
||||||
|
|
||||||
pair->dp_key = chunk_sprintf(label, "%s", key);
|
pair->dp_key = chunk_sprintf(label, "%s", key);
|
||||||
if (regexp)
|
if (regexp)
|
||||||
|
|
@ -451,7 +451,7 @@ db_regexp(char *file,
|
||||||
}
|
}
|
||||||
if ( ! noval) {
|
if ( ! noval) {
|
||||||
if (vlen){
|
if (vlen){
|
||||||
pair->dp_val = chunkdup (val, vlen, label);
|
pair->dp_val = chunkdup(val, vlen, label);
|
||||||
if (pair->dp_val == NULL) {
|
if (pair->dp_val == NULL) {
|
||||||
clicon_err(OE_DB, errno, "%s: chunkdup", __FUNCTION__);
|
clicon_err(OE_DB, errno, "%s: chunkdup", __FUNCTION__);
|
||||||
goto quit;
|
goto quit;
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,8 @@
|
||||||
#include <clixon/clixon_options.h>
|
#include <clixon/clixon_options.h>
|
||||||
#include <clixon/clixon_xml_map.h>
|
#include <clixon/clixon_xml_map.h>
|
||||||
#include <clixon/clixon_xml_db.h>
|
#include <clixon/clixon_xml_db.h>
|
||||||
|
#include <clixon/clixon_xpath_ctx.h>
|
||||||
|
#include <clixon/clixon_xpath.h>
|
||||||
#include <clixon/clixon_xsl.h>
|
#include <clixon/clixon_xsl.h>
|
||||||
#include <clixon/clixon_json.h>
|
#include <clixon/clixon_json.h>
|
||||||
#include <clixon/clixon_netconf_lib.h>
|
#include <clixon/clixon_netconf_lib.h>
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@ static const map_str2int atmap[] = {
|
||||||
{NULL, -1}
|
{NULL, -1}
|
||||||
};
|
};
|
||||||
* @endcode
|
* @endcode
|
||||||
|
* @see clicon_int2str
|
||||||
|
* @see clicon_str2int
|
||||||
*/
|
*/
|
||||||
struct map_str2int{
|
struct map_str2int{
|
||||||
char *ms_str;
|
char *ms_str;
|
||||||
|
|
|
||||||
95
lib/clixon/clixon_xpath.h
Normal file
95
lib/clixon/clixon_xpath.h
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
Copyright (C) 2009-2018 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 *****
|
||||||
|
|
||||||
|
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
|
||||||
|
*/
|
||||||
|
#ifndef _CLIXON_XPATH_H
|
||||||
|
#define _CLIXON_XPATH_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Types
|
||||||
|
*/
|
||||||
|
enum xp_op{
|
||||||
|
XO_AND,
|
||||||
|
XO_OR,
|
||||||
|
XO_DIV,
|
||||||
|
XO_MOD,
|
||||||
|
XO_ADD,
|
||||||
|
XO_MULT,
|
||||||
|
XO_SUB,
|
||||||
|
XO_EQ,
|
||||||
|
XO_NE,
|
||||||
|
XO_GE,
|
||||||
|
XO_LE,
|
||||||
|
XO_LT,
|
||||||
|
XO_GT,
|
||||||
|
XO_UNION,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Axis specifiers according to https://www.w3.org/TR/xpath-10/#NT-AxisName */
|
||||||
|
enum axis_type{
|
||||||
|
A_NAN = 0, /* Not set */
|
||||||
|
A_ANCESTOR,
|
||||||
|
A_ANCESTOR_OR_SELF,
|
||||||
|
A_ATTRIBUTE,
|
||||||
|
A_CHILD,
|
||||||
|
A_DESCENDANT,
|
||||||
|
A_DESCENDANT_OR_SELF,
|
||||||
|
A_FOLLOWING,
|
||||||
|
A_FOLLOWING_SIBLING,
|
||||||
|
A_NAMESPACE,
|
||||||
|
A_PARENT,
|
||||||
|
A_PRECEEDING,
|
||||||
|
A_PRECEEDING_SIBLING,
|
||||||
|
A_SELF,
|
||||||
|
A_ROOT /* XXX Not in https://www.w3.org/TR/xpath-10 */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Variables
|
||||||
|
*/
|
||||||
|
extern const map_str2int xpopmap[];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prototypes
|
||||||
|
*/
|
||||||
|
#if defined(__GNUC__) && __GNUC__ >= 3
|
||||||
|
int xpath_vec_nodeset(cxobj *xcur, char *format, cxobj ***vec, size_t *veclen, ...) __attribute__ ((format (printf, 2, 5)));
|
||||||
|
int xpath_vec_bool(cxobj *xcur, char *format, ...) __attribute__ ((format (printf, 2, 3)));
|
||||||
|
#else
|
||||||
|
int xpath_vec_nodeset(cxobj *xcur, char *format, cxobj ***vec, size_t *veclen, ...);
|
||||||
|
int xpath_vec_bool(cxobj *xcur, char *format, ...);
|
||||||
|
#endif
|
||||||
|
int xpath_vec_ctx(cxobj *xcur, char *xpath, xp_ctx **xrp);
|
||||||
|
|
||||||
|
#endif /* _CLIXON_XPATH_H */
|
||||||
103
lib/clixon/clixon_xpath_ctx.h
Normal file
103
lib/clixon/clixon_xpath_ctx.h
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
Copyright (C) 2009-2018 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 *****
|
||||||
|
|
||||||
|
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
|
||||||
|
* This file defines XPATH contexts using in traversing the XPATH parse tree.
|
||||||
|
*/
|
||||||
|
#ifndef _CLIXON_XPATH_CTX_H
|
||||||
|
#define _CLIXON_XPATH_CTX_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Types
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! XPATH expression type
|
||||||
|
* An expression is evaluated to yield an object, which has one of the following four basic types:
|
||||||
|
* node-set (an unordered collection of nodes without duplicates)
|
||||||
|
* boolean (true or false)
|
||||||
|
* number (a floating-point number)
|
||||||
|
* string (a sequence of UCS characters)
|
||||||
|
*/
|
||||||
|
enum xp_objtype{
|
||||||
|
XT_NODESET,
|
||||||
|
XT_BOOL,
|
||||||
|
XT_NUMBER,
|
||||||
|
XT_STRING
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Expression evaluation occurs with respect to a context. XSLT and XPointer specify how the context is
|
||||||
|
* determined for XPath expressions used in XSLT and XPointer respectively. The context consists of:
|
||||||
|
* a node (the context node)
|
||||||
|
* a pair of non-zero positive integers (the context position and the context size)
|
||||||
|
* a set of variable bindings
|
||||||
|
* a function library
|
||||||
|
* the set of namespace declarations in scope for the expression
|
||||||
|
|
||||||
|
* For each node in the node-set to be filtered, the PredicateExpr is
|
||||||
|
* evaluated with that node as the context node, with the number of nodes
|
||||||
|
* in the node-set as the context size, and with the proximity position
|
||||||
|
* of the node in the node-set with respect to the axis as the context
|
||||||
|
* position; if PredicateExpr evaluates to true for that node, the node
|
||||||
|
* is included in the new node-set; otherwise, it is not included.
|
||||||
|
*/
|
||||||
|
struct xp_ctx{
|
||||||
|
enum xp_objtype xc_type;
|
||||||
|
cxobj **xc_nodeset; /* if type XT_NODESET */
|
||||||
|
size_t xc_size; /* Length of nodeset */
|
||||||
|
int xc_bool; /* if xc_type XT_BOOL */
|
||||||
|
double xc_number; /* if xc_type XT_NUMBER */
|
||||||
|
char *xc_string; /* if xc_type XT_STRING */
|
||||||
|
cxobj *xc_node; /* Node in nodeset XXX maybe not needed*/
|
||||||
|
cxobj *xc_initial; /* RFC 7960 10.1.1 extension: for current() */
|
||||||
|
int xc_descendant; /* // */
|
||||||
|
/* NYI: a set of variable bindings, set of namespace declarations */
|
||||||
|
};
|
||||||
|
typedef struct xp_ctx xp_ctx;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Variables
|
||||||
|
*/
|
||||||
|
extern const map_str2int ctxmap[];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prototypes
|
||||||
|
*/
|
||||||
|
int ctx_free(xp_ctx *xc);
|
||||||
|
xp_ctx *ctx_dup(xp_ctx *xc);
|
||||||
|
int ctx_nodeset_replace(xp_ctx *xc, cxobj **vec, size_t veclen);
|
||||||
|
int ctx_print(cbuf *cb, int id, xp_ctx *xc, char *str);
|
||||||
|
int ctx2boolean(xp_ctx *xc);
|
||||||
|
int ctx2string(xp_ctx *xc, char **str0);
|
||||||
|
int ctx2number(xp_ctx *xc, double *n0);
|
||||||
|
|
||||||
|
#endif /* _CLIXON_XPATH_CTX_H */
|
||||||
|
|
@ -72,18 +72,19 @@ SRC = clixon_sig.c clixon_log.c clixon_err.c clixon_event.c \
|
||||||
clixon_json.c clixon_yang.c clixon_yang_type.c \
|
clixon_json.c clixon_yang.c clixon_yang_type.c \
|
||||||
clixon_hash.c clixon_options.c clixon_plugin.c \
|
clixon_hash.c clixon_options.c clixon_plugin.c \
|
||||||
clixon_proto.c clixon_proto_client.c \
|
clixon_proto.c clixon_proto_client.c \
|
||||||
clixon_xsl.c clixon_sha1.c clixon_xml_db.c clixon_netconf_lib.c
|
clixon_xsl.c clixon_xpath.c clixon_xpath_ctx.c clixon_sha1.c \
|
||||||
|
clixon_xml_db.c clixon_netconf_lib.c
|
||||||
|
|
||||||
YACCOBJS := lex.clixon_xml_parse.o clixon_xml_parse.tab.o \
|
YACCOBJS := lex.clixon_xml_parse.o clixon_xml_parse.tab.o \
|
||||||
lex.clixon_yang_parse.o clixon_yang_parse.tab.o \
|
lex.clixon_yang_parse.o clixon_yang_parse.tab.o \
|
||||||
lex.clixon_json_parse.o clixon_json_parse.tab.o
|
lex.clixon_json_parse.o clixon_json_parse.tab.o \
|
||||||
|
lex.clixon_xpath_parse.o clixon_xpath_parse.tab.o
|
||||||
|
|
||||||
# Extra applications. Utilities, unit testings. Not installed.
|
# Extra applications. Utilities, unit testings. Not installed.
|
||||||
APPSRC = clixon_util_xml.c
|
APPSRC = clixon_util_xml.c
|
||||||
APPSRC += clixon_util_json.c
|
APPSRC += clixon_util_json.c
|
||||||
APPSRC += clixon_util_yang.c
|
APPSRC += clixon_util_yang.c
|
||||||
APPSRC += clixon_util_xsl.c
|
APPSRC += clixon_util_xpath.c
|
||||||
|
|
||||||
APPS = $(APPSRC:.c=)
|
APPS = $(APPSRC:.c=)
|
||||||
|
|
||||||
|
|
@ -107,9 +108,11 @@ clean:
|
||||||
rm -f clixon_xml_parse.tab.[ch] clixon_xml_parse.yy.[co]
|
rm -f clixon_xml_parse.tab.[ch] clixon_xml_parse.yy.[co]
|
||||||
rm -f clixon_yang_parse.tab.[ch] clixon_yang_parse.[co]
|
rm -f clixon_yang_parse.tab.[ch] clixon_yang_parse.[co]
|
||||||
rm -f clixon_json_parse.tab.[ch] clixon_json_parse.[co]
|
rm -f clixon_json_parse.tab.[ch] clixon_json_parse.[co]
|
||||||
|
rm -f clixon_xpath_parse.tab.[ch] clixon_xpath_parse.[co]
|
||||||
rm -f lex.clixon_xml_parse.c
|
rm -f lex.clixon_xml_parse.c
|
||||||
rm -f lex.clixon_yang_parse.c
|
rm -f lex.clixon_yang_parse.c
|
||||||
rm -f lex.clixon_json_parse.c
|
rm -f lex.clixon_json_parse.c
|
||||||
|
rm -f lex.clixon_xpath_parse.c
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
# Implicit rules for lex and yacc.
|
# Implicit rules for lex and yacc.
|
||||||
|
|
@ -159,6 +162,18 @@ clixon_json_parse.tab.c clixon_json_parse.tab.h: clixon_json_parse.y
|
||||||
lex.clixon_json_parse.o : lex.clixon_json_parse.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 $<
|
$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -Wno-error -c $<
|
||||||
|
|
||||||
|
# xpath parser
|
||||||
|
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
|
||||||
|
$(YACC) -l -d -p clixon_xpath_parse clixon_xpath_parse.y # -t is debug
|
||||||
|
mv y.tab.c clixon_xpath_parse.tab.c
|
||||||
|
mv y.tab.h 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 $<
|
||||||
|
|
||||||
# APPS
|
# APPS
|
||||||
clixon_util_xml: clixon_util_xml.c $(MYLIB)
|
clixon_util_xml: clixon_util_xml.c $(MYLIB)
|
||||||
$(CC) $(INCLUDES) $(CPPFLAGS) @CFLAGS@ $^ $(LIBS) -o $@
|
$(CC) $(INCLUDES) $(CPPFLAGS) @CFLAGS@ $^ $(LIBS) -o $@
|
||||||
|
|
@ -169,7 +184,7 @@ clixon_util_json: clixon_util_json.c $(MYLIB)
|
||||||
clixon_util_yang: clixon_util_yang.c $(MYLIB)
|
clixon_util_yang: clixon_util_yang.c $(MYLIB)
|
||||||
$(CC) $(INCLUDES) $(CPPFLAGS) @CFLAGS@ $^ $(LIBS) -o $@
|
$(CC) $(INCLUDES) $(CPPFLAGS) @CFLAGS@ $^ $(LIBS) -o $@
|
||||||
|
|
||||||
clixon_util_xsl: clixon_util_xsl.c $(MYLIB)
|
clixon_util_xpath: clixon_util_xpath.c $(MYLIB)
|
||||||
$(CC) $(INCLUDES) $(CPPFLAGS) @CFLAGS@ $^ $(LIBS) -o $@
|
$(CC) $(INCLUDES) $(CPPFLAGS) @CFLAGS@ $^ $(LIBS) -o $@
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
|
|
|
||||||
|
|
@ -52,24 +52,24 @@
|
||||||
* clicon_hash_t *hash = hash_init();
|
* clicon_hash_t *hash = hash_init();
|
||||||
*
|
*
|
||||||
* n = 234;
|
* n = 234;
|
||||||
* hash_add (hash, "APA", &n, sizeof(n));
|
* hash_add(hash, "APA", &n, sizeof(n));
|
||||||
* hash_dump(hash, stdout);
|
* hash_dump(hash, stdout);
|
||||||
*
|
*
|
||||||
* puts("----");
|
* puts("----");
|
||||||
*
|
*
|
||||||
* hash_add (hash, "BEPA", "hoppla Polle!", strlen("hoppla Polle!")+1);
|
* hash_add(hash, "BEPA", "hoppla Polle!", strlen("hoppla Polle!")+1);
|
||||||
* puts((char *)hash_value(hash, "BEPA", NULL));
|
* puts((char *)hash_value(hash, "BEPA", NULL));
|
||||||
* hash_dump(hash, stdout);
|
* hash_dump(hash, stdout);
|
||||||
*
|
*
|
||||||
* puts("----");
|
* puts("----");
|
||||||
*
|
*
|
||||||
* n = 33;
|
* n = 33;
|
||||||
* hash_add (hash, "CEPA", &n, sizeof(n));
|
* hash_add(hash, "CEPA", &n, sizeof(n));
|
||||||
* hash_dump(hash, stdout);
|
* hash_dump(hash, stdout);
|
||||||
*
|
*
|
||||||
* puts("----");
|
* puts("----");
|
||||||
*
|
*
|
||||||
* hash_del (hash, "APA");
|
* hash_del(hash, "APA");
|
||||||
* hash_dump(hash, stdout);
|
* hash_dump(hash, stdout);
|
||||||
*
|
*
|
||||||
* hash_free(hash);
|
* hash_free(hash);
|
||||||
|
|
@ -118,11 +118,11 @@ hash_init (void)
|
||||||
{
|
{
|
||||||
clicon_hash_t *hash;
|
clicon_hash_t *hash;
|
||||||
|
|
||||||
if ((hash = (clicon_hash_t *)malloc (sizeof (clicon_hash_t) * HASH_SIZE)) == NULL){
|
if ((hash = (clicon_hash_t *)malloc(sizeof(clicon_hash_t) * HASH_SIZE)) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "malloc: %s", strerror(errno));
|
clicon_err(OE_UNIX, errno, "malloc: %s", strerror(errno));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
memset (hash, 0, sizeof(clicon_hash_t)*HASH_SIZE);
|
memset(hash, 0, sizeof(clicon_hash_t)*HASH_SIZE);
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -167,7 +167,7 @@ hash_lookup(clicon_hash_t *hash,
|
||||||
h = hash[bkt];
|
h = hash[bkt];
|
||||||
if (h) {
|
if (h) {
|
||||||
do {
|
do {
|
||||||
if (!strcmp (h->h_key, key))
|
if (!strcmp(h->h_key, key))
|
||||||
return h;
|
return h;
|
||||||
h = NEXTQ(clicon_hash_t, h);
|
h = NEXTQ(clicon_hash_t, h);
|
||||||
} while (h != hash[bkt]);
|
} while (h != hash[bkt]);
|
||||||
|
|
@ -218,15 +218,15 @@ hash_add(clicon_hash_t *hash,
|
||||||
clicon_hash_t new = NULL;
|
clicon_hash_t new = NULL;
|
||||||
|
|
||||||
/* If variable exist, don't allocate a new. just replace value */
|
/* If variable exist, don't allocate a new. just replace value */
|
||||||
h = hash_lookup (hash, key);
|
h = hash_lookup(hash, key);
|
||||||
if (h == NULL) {
|
if (h == NULL) {
|
||||||
if ((new = (clicon_hash_t)malloc (sizeof (*new))) == NULL){
|
if ((new = (clicon_hash_t)malloc(sizeof(*new))) == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "malloc: %s", strerror(errno));
|
clicon_err(OE_UNIX, errno, "malloc: %s", strerror(errno));
|
||||||
goto catch;
|
goto catch;
|
||||||
}
|
}
|
||||||
memset (new, 0, sizeof (*new));
|
memset(new, 0, sizeof(*new));
|
||||||
|
|
||||||
new->h_key = strdup (key);
|
new->h_key = strdup(key);
|
||||||
if (new->h_key == NULL){
|
if (new->h_key == NULL){
|
||||||
clicon_err(OE_UNIX, errno, "strdup: %s", strerror(errno));
|
clicon_err(OE_UNIX, errno, "strdup: %s", strerror(errno));
|
||||||
goto catch;
|
goto catch;
|
||||||
|
|
@ -241,11 +241,11 @@ hash_add(clicon_hash_t *hash,
|
||||||
clicon_err(OE_UNIX, errno, "malloc: %s", strerror(errno));
|
clicon_err(OE_UNIX, errno, "malloc: %s", strerror(errno));
|
||||||
goto catch;
|
goto catch;
|
||||||
}
|
}
|
||||||
memcpy (newval, val, vlen);
|
memcpy(newval, val, vlen);
|
||||||
|
|
||||||
/* Free old value if existing variable */
|
/* Free old value if existing variable */
|
||||||
if (h->h_val)
|
if (h->h_val)
|
||||||
free (h->h_val);
|
free(h->h_val);
|
||||||
h->h_val = newval;
|
h->h_val = newval;
|
||||||
h->h_vlen = vlen;
|
h->h_vlen = vlen;
|
||||||
|
|
||||||
|
|
@ -258,8 +258,8 @@ hash_add(clicon_hash_t *hash,
|
||||||
catch:
|
catch:
|
||||||
if (new) {
|
if (new) {
|
||||||
if (new->h_key)
|
if (new->h_key)
|
||||||
free (new->h_key);
|
free(new->h_key);
|
||||||
free (new);
|
free(new);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -279,15 +279,15 @@ hash_del(clicon_hash_t *hash,
|
||||||
{
|
{
|
||||||
clicon_hash_t h;
|
clicon_hash_t h;
|
||||||
|
|
||||||
h = hash_lookup (hash, key);
|
h = hash_lookup(hash, key);
|
||||||
if (h == NULL)
|
if (h == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
DELQ(h, hash[hash_bucket(key)], clicon_hash_t);
|
DELQ(h, hash[hash_bucket(key)], clicon_hash_t);
|
||||||
|
|
||||||
free (h->h_key);
|
free(h->h_key);
|
||||||
free (h->h_val);
|
free(h->h_val);
|
||||||
free (h);
|
free(h);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -140,11 +140,11 @@ clicon_strjoin(int argc,
|
||||||
len += 1; /* '\0' */
|
len += 1; /* '\0' */
|
||||||
if ((str = malloc(len)) == NULL)
|
if ((str = malloc(len)) == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
memset (str, '\0', len);
|
memset(str, '\0', len);
|
||||||
for (i = 0; i < argc; i++) {
|
for (i = 0; i < argc; i++) {
|
||||||
if (i != 0)
|
if (i != 0)
|
||||||
strncat (str, delim, len - strlen(str));
|
strncat(str, delim, len - strlen(str));
|
||||||
strncat (str, argv[i], len - strlen(str));
|
strncat(str, argv[i], len - strlen(str));
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
@ -518,21 +518,21 @@ clicon_str2int(const map_str2int *mstab,
|
||||||
*/
|
*/
|
||||||
#ifndef HAVE_STRNDUP
|
#ifndef HAVE_STRNDUP
|
||||||
char *
|
char *
|
||||||
clicon_strndup (const char *str,
|
clicon_strndup(const char *str,
|
||||||
size_t len)
|
size_t len)
|
||||||
{
|
{
|
||||||
char *new;
|
char *new;
|
||||||
size_t slen;
|
size_t slen;
|
||||||
|
|
||||||
slen = strlen (str);
|
slen = strlen(str);
|
||||||
len = (len < slen ? len : slen);
|
len = (len < slen ? len : slen);
|
||||||
|
|
||||||
new = malloc (len + 1);
|
new = malloc(len + 1);
|
||||||
if (new == NULL)
|
if (new == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
new[len] = '\0';
|
new[len] = '\0';
|
||||||
memcpy (new, str, len);
|
memcpy(new, str, len);
|
||||||
|
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
231
lib/src/clixon_util_xpath.c
Normal file
231
lib/src/clixon_util_xpath.c
Normal file
|
|
@ -0,0 +1,231 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
Copyright (C) 2009-2018 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 *****
|
||||||
|
|
||||||
|
See https://www.w3.org/TR/xpath/
|
||||||
|
|
||||||
|
* Turn this on to get an xpath test program
|
||||||
|
* Usage: xpath [<xpath>]
|
||||||
|
* read xpath on first line and xml on rest of lines from input
|
||||||
|
* Example compile:
|
||||||
|
gcc -g -o xpath -I. -I../clixon ./clixon_xsl.c -lclixon -lcligen
|
||||||
|
* Example run:
|
||||||
|
echo "a\n<a><b/></a>" | xpath
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "clixon_config.h" /* generated by config & autoconf */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <fnmatch.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
/* cligen */
|
||||||
|
#include <cligen/cligen.h>
|
||||||
|
|
||||||
|
/* clixon */
|
||||||
|
#include <clixon/clixon.h>
|
||||||
|
|
||||||
|
static int
|
||||||
|
usage(char *argv0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "usage:%s [options]\n"
|
||||||
|
"where options are\n"
|
||||||
|
"\t-h \t\tHelp\n"
|
||||||
|
"\t-D <level> \tDebug\n"
|
||||||
|
"\t-f <file> \tXML file\n"
|
||||||
|
"\t-p <xpath> \tPrimary XPATH string\n"
|
||||||
|
"\t-i <xpath0>\t(optional) Initial XPATH string\n"
|
||||||
|
"and the following extra rules:\n"
|
||||||
|
"\tif -f is not given, XML input is expected on stdin\n"
|
||||||
|
"\tif -p is not given, <xpath> is expected as the first line on stdin\n"
|
||||||
|
"This means that with no arguments, <xpath> and XML is expected on stadin.\n",
|
||||||
|
argv0
|
||||||
|
);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ctx_print2(cbuf *cb,
|
||||||
|
xp_ctx *xc)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
cprintf(cb, "%s:", (char*)clicon_int2str(ctxmap, xc->xc_type));
|
||||||
|
switch (xc->xc_type){
|
||||||
|
case XT_NODESET:
|
||||||
|
for (i=0; i<xc->xc_size; i++){
|
||||||
|
cprintf(cb, "%d:", i);
|
||||||
|
clicon_xml2cbuf(cb, xc->xc_nodeset[i], 0, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XT_BOOL:
|
||||||
|
cprintf(cb, "%s", xc->xc_bool?"true":"false");
|
||||||
|
break;
|
||||||
|
case XT_NUMBER:
|
||||||
|
cprintf(cb, "%lf", xc->xc_number);
|
||||||
|
break;
|
||||||
|
case XT_STRING:
|
||||||
|
cprintf(cb, "%s", xc->xc_string);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
char *argv0 = argv[0];
|
||||||
|
int i;
|
||||||
|
cxobj **xv = NULL;
|
||||||
|
cxobj *x0 = NULL;
|
||||||
|
cxobj *x;
|
||||||
|
char c;
|
||||||
|
int len;
|
||||||
|
char *buf = NULL;
|
||||||
|
int ret;
|
||||||
|
int fd = 0; /* unless overriden by argv[1] */
|
||||||
|
char *xpath = NULL;
|
||||||
|
char *xpath0 = NULL;
|
||||||
|
char *filename;
|
||||||
|
xp_ctx *xc = NULL;
|
||||||
|
cbuf *cb;
|
||||||
|
|
||||||
|
clicon_log_init("xpath", LOG_DEBUG, CLICON_LOG_STDERR);
|
||||||
|
optind = 1;
|
||||||
|
opterr = 0;
|
||||||
|
while ((c = getopt(argc, argv, "hDf:p:i:")) != -1)
|
||||||
|
switch (c) {
|
||||||
|
case 'h':
|
||||||
|
usage(argv0);
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
debug++;
|
||||||
|
break;
|
||||||
|
case 'f': /* XML file */
|
||||||
|
filename = optarg;
|
||||||
|
if ((fd = open(filename, O_RDONLY)) < 0){
|
||||||
|
clicon_err(OE_UNIX, errno, "open(%s)", argv[1]);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'p': /* Primary XPATH string */
|
||||||
|
xpath = optarg;
|
||||||
|
break;
|
||||||
|
case 'i': /* Optional initial XPATH string */
|
||||||
|
xpath0 = optarg;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage(argv[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (xpath==NULL){
|
||||||
|
/* First read xpath */
|
||||||
|
len = 1024; /* any number is fine */
|
||||||
|
if ((buf = malloc(len)) == NULL){
|
||||||
|
perror("pt_file malloc");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memset(buf, 0, len);
|
||||||
|
i = 0;
|
||||||
|
while (1){
|
||||||
|
if ((ret = read(0, &c, 1)) < 0){
|
||||||
|
perror("read");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (ret == 0)
|
||||||
|
break;
|
||||||
|
if (c == '\n')
|
||||||
|
break;
|
||||||
|
if (len==i){
|
||||||
|
if ((buf = realloc(buf, 2*len)) == NULL){
|
||||||
|
fprintf(stderr, "%s: realloc: %s\n", __FUNCTION__, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memset(buf+len, 0, len);
|
||||||
|
len *= 2;
|
||||||
|
}
|
||||||
|
buf[i++] = (char)(c&0xff);
|
||||||
|
}
|
||||||
|
xpath = buf;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* If fd=0, then continue reading from stdin (after CR)
|
||||||
|
* If fd>0, reading from file opened as argv[1]
|
||||||
|
*/
|
||||||
|
if (xml_parse_file(fd, "</clicon>", NULL, &x0) < 0){
|
||||||
|
fprintf(stderr, "Error: parsing: %s\n", clicon_err_reason);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* If xpath0 given, position current x */
|
||||||
|
if (xpath0){
|
||||||
|
if ((x = xpath_first(x0, "%s", xpath0)) == NULL){
|
||||||
|
fprintf(stderr, "Error: xpath0 returned NULL\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
x = x0;
|
||||||
|
|
||||||
|
/* Parse XML */
|
||||||
|
if (xpath_vec_ctx(x, xpath, &xc) < 0)
|
||||||
|
return -1;
|
||||||
|
/* Print results */
|
||||||
|
cb = cbuf_new();
|
||||||
|
ctx_print2(cb, xc);
|
||||||
|
fprintf(stdout, "%s\n", cbuf_get(cb));
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (cb)
|
||||||
|
cbuf_free(cb);
|
||||||
|
if (xc)
|
||||||
|
ctx_free(xc);
|
||||||
|
if (xv)
|
||||||
|
free(xv);
|
||||||
|
if (buf)
|
||||||
|
free(buf);
|
||||||
|
if (x0)
|
||||||
|
xml_free(x0);
|
||||||
|
if (fd > 0)
|
||||||
|
close(fd);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
@ -1,141 +0,0 @@
|
||||||
/*
|
|
||||||
*
|
|
||||||
***** BEGIN LICENSE BLOCK *****
|
|
||||||
|
|
||||||
Copyright (C) 2009-2018 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 *****
|
|
||||||
|
|
||||||
See https://www.w3.org/TR/xpath/
|
|
||||||
|
|
||||||
* Turn this on to get an xpath test program
|
|
||||||
* Usage: xpath [<xpath>]
|
|
||||||
* read xpath on first line and xml on rest of lines from input
|
|
||||||
* Example compile:
|
|
||||||
gcc -g -o xpath -I. -I../clixon ./clixon_xsl.c -lclixon -lcligen
|
|
||||||
* Example run:
|
|
||||||
echo "a\n<a><b/></a>" | xpath
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "clixon_config.h" /* generated by config & autoconf */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <fnmatch.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <syslog.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
/* cligen */
|
|
||||||
#include <cligen/cligen.h>
|
|
||||||
|
|
||||||
/* clixon */
|
|
||||||
#include <clixon/clixon.h>
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
usage(char *argv0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "usage:%s <xpath>.\n\tInput on stdin\n", argv0);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
int i;
|
|
||||||
cxobj **xv;
|
|
||||||
cxobj *x;
|
|
||||||
cxobj *xn;
|
|
||||||
size_t xlen = 0;
|
|
||||||
int c;
|
|
||||||
int len;
|
|
||||||
char *buf = NULL;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (argc != 1){
|
|
||||||
usage(argv[0]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
/* First read xpath */
|
|
||||||
len = 1024; /* any number is fine */
|
|
||||||
if ((buf = malloc(len)) == NULL){
|
|
||||||
perror("pt_file malloc");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
memset(buf, 0, len);
|
|
||||||
i = 0;
|
|
||||||
while (1){
|
|
||||||
if ((ret = read(0, &c, 1)) < 0){
|
|
||||||
perror("read");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (ret == 0)
|
|
||||||
break;
|
|
||||||
if (c == '\n')
|
|
||||||
break;
|
|
||||||
if (len==i){
|
|
||||||
if ((buf = realloc(buf, 2*len)) == NULL){
|
|
||||||
fprintf(stderr, "%s: realloc: %s\n", __FUNCTION__, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
memset(buf+len, 0, len);
|
|
||||||
len *= 2;
|
|
||||||
}
|
|
||||||
buf[i++] = (char)(c&0xff);
|
|
||||||
}
|
|
||||||
x = NULL;
|
|
||||||
if (xml_parse_file(0, "</clicon>", NULL, &x) < 0){
|
|
||||||
fprintf(stderr, "Error: parsing: %s\n", clicon_err_reason);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (xpath_vec(x, "%s", &xv, &xlen, buf) < 0)
|
|
||||||
return -1;
|
|
||||||
if (xv){
|
|
||||||
for (i=0; i<xlen; i++){
|
|
||||||
xn = xv[i];
|
|
||||||
fprintf(stdout, "%d:", i);
|
|
||||||
clicon_xml2file(stdout, xn, 0, 0);
|
|
||||||
fprintf(stdout, "\n");
|
|
||||||
}
|
|
||||||
free(xv);
|
|
||||||
}
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
if (x)
|
|
||||||
xml_free(x);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
@ -1487,8 +1487,6 @@ int
|
||||||
xml_copy_one(cxobj *x0,
|
xml_copy_one(cxobj *x0,
|
||||||
cxobj *x1)
|
cxobj *x1)
|
||||||
{
|
{
|
||||||
cg_var *cv1;
|
|
||||||
|
|
||||||
xml_type_set(x1, xml_type(x0));
|
xml_type_set(x1, xml_type(x0));
|
||||||
if (xml_value(x0)){ /* malloced string */
|
if (xml_value(x0)){ /* malloced string */
|
||||||
if ((x1->x_value = strdup(x0->x_value)) == NULL){
|
if ((x1->x_value = strdup(x0->x_value)) == NULL){
|
||||||
|
|
|
||||||
|
|
@ -424,13 +424,15 @@ xml_yang_validate_all(cxobj *xt,
|
||||||
void *arg)
|
void *arg)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
yang_stmt *ys;
|
yang_stmt *ys; /* yang node */
|
||||||
yang_stmt *ytype;
|
yang_stmt *yc; /* yang child */
|
||||||
|
char *xpath;
|
||||||
|
|
||||||
/* if not given by argument (overide) use default link
|
/* if not given by argument (overide) use default link
|
||||||
and !Node has a config sub-statement and it is false */
|
and !Node has a config sub-statement and it is false */
|
||||||
if ((ys = xml_spec(xt)) != NULL &&
|
if ((ys = xml_spec(xt)) != NULL &&
|
||||||
yang_config(ys) != 0){
|
yang_config(ys) != 0){
|
||||||
|
/* Node-specific validation */
|
||||||
switch (ys->ys_keyword){
|
switch (ys->ys_keyword){
|
||||||
case Y_LEAF:
|
case Y_LEAF:
|
||||||
/* fall thru */
|
/* fall thru */
|
||||||
|
|
@ -438,20 +440,29 @@ xml_yang_validate_all(cxobj *xt,
|
||||||
/* Special case if leaf is leafref, then first check against
|
/* Special case if leaf is leafref, then first check against
|
||||||
current xml tree
|
current xml tree
|
||||||
*/
|
*/
|
||||||
if ((ytype = yang_find((yang_node*)ys, Y_TYPE, NULL)) != NULL){
|
if ((yc = yang_find((yang_node*)ys, Y_TYPE, NULL)) != NULL){
|
||||||
if (strcmp(ytype->ys_argument, "leafref") == 0){
|
if (strcmp(yc->ys_argument, "leafref") == 0){
|
||||||
if (validate_leafref(xt, ytype) < 0)
|
if (validate_leafref(xt, yc) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
else if (strcmp(ytype->ys_argument, "identityref") == 0){
|
else if (strcmp(yc->ys_argument, "identityref") == 0){
|
||||||
if (validate_identityref(xt, ys, ytype) < 0)
|
if (validate_identityref(xt, ys, yc) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Y_MUST: /* RFC 7950 Sec 7.5.3 */
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* "when" sub-node RFC 7950 Sec 7.21.5 */
|
||||||
|
if ((yc = yang_find((yang_node*)ys, Y_WHEN, NULL)) != NULL){
|
||||||
|
xpath = yc->ys_argument; /* "when" has xpath argument */
|
||||||
|
if (xpath_first(xt, "%s", xpath))
|
||||||
|
;
|
||||||
|
fprintf(stderr, "%s %s\n", __FUNCTION__, xpath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
done:
|
done:
|
||||||
|
|
@ -1372,7 +1383,6 @@ xml_spec_populate(cxobj *x,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! Translate from restconf api-path in cvv form to xml xpath
|
/*! Translate from restconf api-path in cvv form to xml xpath
|
||||||
* eg a/b=c -> a/[b=c]
|
* eg a/b=c -> a/[b=c]
|
||||||
* @param[in] yspec Yang spec
|
* @param[in] yspec Yang spec
|
||||||
|
|
|
||||||
1183
lib/src/clixon_xpath.c
Normal file
1183
lib/src/clixon_xpath.c
Normal file
File diff suppressed because it is too large
Load diff
294
lib/src/clixon_xpath_ctx.c
Normal file
294
lib/src/clixon_xpath_ctx.c
Normal file
|
|
@ -0,0 +1,294 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
Copyright (C) 2009-2018 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 *****
|
||||||
|
|
||||||
|
* Clixon XML XPATH 1.0 according to https://www.w3.org/TR/xpath-10
|
||||||
|
* This file defines XPATH contexts using in traversing the XPATH parse tree.
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <fnmatch.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
/* cligen */
|
||||||
|
#include <cligen/cligen.h>
|
||||||
|
|
||||||
|
/* clicon */
|
||||||
|
#include "clixon_err.h"
|
||||||
|
#include "clixon_log.h"
|
||||||
|
#include "clixon_string.h"
|
||||||
|
#include "clixon_queue.h"
|
||||||
|
#include "clixon_hash.h"
|
||||||
|
#include "clixon_handle.h"
|
||||||
|
#include "clixon_yang.h"
|
||||||
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_xpath_parse.h"
|
||||||
|
#include "clixon_xpath_ctx.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Variables
|
||||||
|
*/
|
||||||
|
const map_str2int ctxmap[] = {
|
||||||
|
{"nodeset", XT_NODESET},
|
||||||
|
{"bool", XT_BOOL},
|
||||||
|
{"number", XT_NUMBER},
|
||||||
|
{"string", XT_STRING},
|
||||||
|
{NULL, -1}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! Free xpath context */
|
||||||
|
int
|
||||||
|
ctx_free(xp_ctx *xc)
|
||||||
|
{
|
||||||
|
if (xc->xc_nodeset)
|
||||||
|
free(xc->xc_nodeset);
|
||||||
|
if (xc->xc_string)
|
||||||
|
free(xc->xc_string);
|
||||||
|
free(xc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Duplicate xpath context */
|
||||||
|
xp_ctx *
|
||||||
|
ctx_dup(xp_ctx *xc0)
|
||||||
|
{
|
||||||
|
static xp_ctx *xc = NULL;
|
||||||
|
|
||||||
|
if ((xc = malloc(sizeof(*xc))) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "malloc");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
memset(xc, 0, sizeof(*xc));
|
||||||
|
*xc = *xc0;
|
||||||
|
if (xc0->xc_size){
|
||||||
|
if ((xc->xc_nodeset = calloc(xc0->xc_size, sizeof(cxobj*))) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "calloc");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
memcpy(xc->xc_nodeset, xc0->xc_nodeset, xc->xc_size*sizeof(cxobj*));
|
||||||
|
}
|
||||||
|
if (xc0->xc_string)
|
||||||
|
if ((xc->xc_string = strdup(xc0->xc_string)) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
return xc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Print XPATH context */
|
||||||
|
int
|
||||||
|
ctx_print(cbuf *cb,
|
||||||
|
int id,
|
||||||
|
xp_ctx *xc,
|
||||||
|
char *str)
|
||||||
|
{
|
||||||
|
static int ident = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (id<0)
|
||||||
|
ident += id;
|
||||||
|
cprintf(cb, "%*s%s ", ident, "", str?str:"");
|
||||||
|
if (id>0)
|
||||||
|
ident += id;
|
||||||
|
if (xc){
|
||||||
|
cprintf(cb, "%s: ", (char*)clicon_int2str(ctxmap, xc->xc_type));
|
||||||
|
switch (xc->xc_type){
|
||||||
|
case XT_NODESET:
|
||||||
|
for (i=0; i<xc->xc_size; i++)
|
||||||
|
cprintf(cb, "%s ", xml_name(xc->xc_nodeset[i]));
|
||||||
|
break;
|
||||||
|
case XT_BOOL:
|
||||||
|
cprintf(cb, "%s", xc->xc_bool?"true":"false");
|
||||||
|
break;
|
||||||
|
case XT_NUMBER:
|
||||||
|
cprintf(cb, "%lf", xc->xc_number);
|
||||||
|
break;
|
||||||
|
case XT_STRING:
|
||||||
|
cprintf(cb, "%s", xc->xc_string);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Convert xpath context to boolean according to boolean() function in XPATH spec
|
||||||
|
* @param[in] xc XPATH context
|
||||||
|
* @retval 0 False
|
||||||
|
* @retval 1 True
|
||||||
|
* a number is true if and only if it is neither positive or negative zero nor NaN
|
||||||
|
* a node-set is true if and only if it is non-empty
|
||||||
|
* a string is true if and only if its length is non-zero
|
||||||
|
* an object of a type other than the four basic types is converted to a boolean
|
||||||
|
* in a way that is dependent on that type
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
ctx2boolean(xp_ctx *xc)
|
||||||
|
{
|
||||||
|
int b;
|
||||||
|
switch (xc->xc_type){
|
||||||
|
case XT_NODESET:
|
||||||
|
b = (xc->xc_size != 0);
|
||||||
|
break;
|
||||||
|
case XT_BOOL:
|
||||||
|
b = xc->xc_bool;
|
||||||
|
break;
|
||||||
|
case XT_NUMBER:
|
||||||
|
b = (xc->xc_number != 0.0 && xc->xc_number != NAN);
|
||||||
|
break;
|
||||||
|
case XT_STRING:
|
||||||
|
b = (xc->xc_string && strlen(xc->xc_string));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Convert xpath context to string according to string() function in XPATH spec
|
||||||
|
* @param[in] xc XPATH context
|
||||||
|
* @param[out] str0 Malloced result string
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
* @note string malloced.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
ctx2string(xp_ctx *xc,
|
||||||
|
char **str0)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
char *str = NULL;
|
||||||
|
int len;
|
||||||
|
char *b;
|
||||||
|
|
||||||
|
switch (xc->xc_type){
|
||||||
|
case XT_NODESET:
|
||||||
|
if (xc->xc_size && (b = xml_body(xc->xc_nodeset[0]))){
|
||||||
|
if ((str = strdup(b)) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if ((str = strdup("")) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XT_BOOL:
|
||||||
|
if ((str = strdup(xc->xc_bool == 0?"false":"true")) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XT_NUMBER:
|
||||||
|
len = snprintf(NULL, 0, "%0lf", xc->xc_number);
|
||||||
|
len++;
|
||||||
|
if ((str = malloc(len)) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "malloc");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
snprintf(str, len, "%0lf", xc->xc_number);
|
||||||
|
break;
|
||||||
|
case XT_STRING:
|
||||||
|
if ((str = strdup(xc->xc_string)) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "strdup");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*str0 = str;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Convert xpath context to number according to number() function in XPATH spec
|
||||||
|
* @param[in] xc XPATH context
|
||||||
|
* @param[out] n0 Floating point or NAN
|
||||||
|
* @retval 0 OK
|
||||||
|
* @retval -1 Error
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
ctx2number(xp_ctx *xc,
|
||||||
|
double *n0)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
char *str = NULL;
|
||||||
|
double n;
|
||||||
|
|
||||||
|
switch (xc->xc_type){
|
||||||
|
case XT_NODESET:
|
||||||
|
if (ctx2string(xc, &str) < 0)
|
||||||
|
goto done;
|
||||||
|
if (sscanf(str, "%lf",&n) != 1)
|
||||||
|
n = NAN;
|
||||||
|
break;
|
||||||
|
case XT_BOOL:
|
||||||
|
n = (double)xc->xc_bool;
|
||||||
|
break;
|
||||||
|
case XT_NUMBER:
|
||||||
|
n = xc->xc_number;
|
||||||
|
break;
|
||||||
|
case XT_STRING:
|
||||||
|
if (sscanf(xc->xc_string, "%lf",&n) != 1)
|
||||||
|
n = NAN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*n0 = n;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (str)
|
||||||
|
free(str);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Replace a nodeset of a XPATH context with a new nodeset
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
ctx_nodeset_replace(xp_ctx *xc,
|
||||||
|
cxobj **vec,
|
||||||
|
size_t veclen)
|
||||||
|
{
|
||||||
|
if (xc->xc_nodeset)
|
||||||
|
free(xc->xc_nodeset);
|
||||||
|
xc->xc_nodeset = vec;
|
||||||
|
xc->xc_size = veclen;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
101
lib/src/clixon_xpath_parse.h
Normal file
101
lib/src/clixon_xpath_parse.h
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
Copyright (C) 2009-2018 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 *****
|
||||||
|
|
||||||
|
*/
|
||||||
|
#ifndef _CLIXON_XPATH_PARSE_H_
|
||||||
|
#define _CLIXON_XPATH_PARSE_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Types
|
||||||
|
*/
|
||||||
|
/* used as non-terminal type in yacc rules */
|
||||||
|
enum xp_type{
|
||||||
|
XP_EXP,
|
||||||
|
XP_AND,
|
||||||
|
XP_RELEX,
|
||||||
|
XP_ADD,
|
||||||
|
XP_UNION,
|
||||||
|
XP_PATHEXPR,
|
||||||
|
XP_LOCPATH,
|
||||||
|
XP_ABSPATH,
|
||||||
|
XP_RELLOCPATH,
|
||||||
|
XP_STEP,
|
||||||
|
XP_NODE,
|
||||||
|
XP_NODE_FN,
|
||||||
|
XP_PRED,
|
||||||
|
XP_PRI0,
|
||||||
|
XP_PRIME_NR,
|
||||||
|
XP_PRIME_STR,
|
||||||
|
XP_PRIME_FN,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*! XPATH Parsing generates a tree of nodes that is later traversed
|
||||||
|
*/
|
||||||
|
struct xpath_tree{
|
||||||
|
enum xp_type xs_type;
|
||||||
|
int xs_int;
|
||||||
|
double xs_double;
|
||||||
|
char *xs_s0;
|
||||||
|
char *xs_s1;
|
||||||
|
struct xpath_tree *xs_c0; /* child 0 */
|
||||||
|
struct xpath_tree *xs_c1; /* child 1 */
|
||||||
|
};
|
||||||
|
typedef struct xpath_tree xpath_tree;
|
||||||
|
|
||||||
|
struct clicon_xpath_yacc_arg{ /* XXX: mostly unrelevant */
|
||||||
|
const char *xy_name; /* Name of syntax (for error string) */
|
||||||
|
int xy_linenum; /* Number of \n in parsed buffer */
|
||||||
|
char *xy_parse_string; /* original (copy of) parse string */
|
||||||
|
void *xy_lexbuf; /* internal parse buffer from lex */
|
||||||
|
xpath_tree *xy_top;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Variables
|
||||||
|
*/
|
||||||
|
extern char *clixon_xpath_parsetext;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prototypes
|
||||||
|
*/
|
||||||
|
int xpath_scan_init(struct clicon_xpath_yacc_arg *jy);
|
||||||
|
int xpath_scan_exit(struct clicon_xpath_yacc_arg *jy);
|
||||||
|
|
||||||
|
int xpath_parse_init(struct clicon_xpath_yacc_arg *jy);
|
||||||
|
int xpath_parse_exit(struct clicon_xpath_yacc_arg *jy);
|
||||||
|
|
||||||
|
int clixon_xpath_parselex(void *);
|
||||||
|
int clixon_xpath_parseparse(void *);
|
||||||
|
void clixon_xpath_parseerror(void *, char*);
|
||||||
|
|
||||||
|
#endif /* _CLIXON_XPATH_PARSE_H_ */
|
||||||
174
lib/src/clixon_xpath_parse.l
Normal file
174
lib/src/clixon_xpath_parse.l
Normal file
|
|
@ -0,0 +1,174 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
Copyright (C) 2009-2018 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 *****
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
%{
|
||||||
|
|
||||||
|
#include "clixon_config.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
#include "clixon_xpath_parse.tab.h" /* generated */
|
||||||
|
|
||||||
|
#include <cligen/cligen.h>
|
||||||
|
|
||||||
|
#include "clixon_queue.h"
|
||||||
|
#include "clixon_hash.h"
|
||||||
|
#include "clixon_handle.h"
|
||||||
|
#include "clixon_yang.h"
|
||||||
|
#include "clixon_log.h"
|
||||||
|
#include "clixon_string.h"
|
||||||
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_xpath_ctx.h"
|
||||||
|
#include "clixon_xpath.h"
|
||||||
|
#include "clixon_xpath_parse.h"
|
||||||
|
|
||||||
|
/* Redefine main lex function so that you can send arguments to it: _yy is added to arg list */
|
||||||
|
#define YY_DECL int clixon_xpath_parselex(void *_yy)
|
||||||
|
|
||||||
|
/* Dont use input function (use user-buffer) */
|
||||||
|
#define YY_NO_INPUT
|
||||||
|
|
||||||
|
/* typecast macro */
|
||||||
|
#define _XY ((struct clicon_xpath_yacc_arg *)_yy)
|
||||||
|
|
||||||
|
#define MAXBUF 4*4*64*1024
|
||||||
|
|
||||||
|
#undef clixon_xpath_parsewrap
|
||||||
|
int
|
||||||
|
clixon_xpath_parsewrap(void)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
digit [0-9]
|
||||||
|
integer {digit}+
|
||||||
|
real ({digit}+[.]{digit}*)|({digit}*[.]{digit}+)
|
||||||
|
|
||||||
|
%x TOKEN
|
||||||
|
%s QLITERAL
|
||||||
|
%s ALITERAL
|
||||||
|
|
||||||
|
%%
|
||||||
|
<TOKEN>[ \t]
|
||||||
|
<TOKEN>\n { _XY->xy_linenum++; }
|
||||||
|
<TOKEN>\r { }
|
||||||
|
<TOKEN><<EOF>> { return X_EOF; }
|
||||||
|
<TOKEN>".." { return DOUBLEDOT; }
|
||||||
|
<TOKEN>[()\[\]\.@,/:|] { return *yytext; }
|
||||||
|
<TOKEN>"::" { return DOUBLECOLON; }
|
||||||
|
<TOKEN>and { clixon_xpath_parselval.intval = clicon_str2int(xpopmap, yytext); return LOGOP; }
|
||||||
|
<TOKEN>or { clixon_xpath_parselval.intval = clicon_str2int(xpopmap, yytext); return LOGOP; }
|
||||||
|
<TOKEN>div { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; }
|
||||||
|
<TOKEN>mod { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; }
|
||||||
|
<TOKEN>[+*\-] { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return ADDOP; }
|
||||||
|
<TOKEN>\? { return *yytext; }
|
||||||
|
<TOKEN>"//" { return DOUBLESLASH; }
|
||||||
|
<TOKEN>"!=" { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext); return RELOP; }
|
||||||
|
<TOKEN>">=" { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; }
|
||||||
|
<TOKEN>"<=" { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; }
|
||||||
|
<TOKEN>[<>=] { clixon_xpath_parselval.intval = clicon_str2int(xpopmap,yytext);return RELOP; }
|
||||||
|
<TOKEN>last { clixon_xpath_parselval.string = strdup(yytext); return FUNCTIONNAME; }
|
||||||
|
<TOKEN>position { clixon_xpath_parselval.string = strdup(yytext); return FUNCTIONNAME; }
|
||||||
|
<TOKEN>count { clixon_xpath_parselval.string = strdup(yytext); return FUNCTIONNAME; }
|
||||||
|
<TOKEN>ancestor { clixon_xpath_parselval.intval = A_ANCESTOR; return AXISNAME; }
|
||||||
|
<TOKEN>ancestor-or-self { clixon_xpath_parselval.intval = A_ANCESTOR_OR_SELF; return AXISNAME; }
|
||||||
|
<TOKEN>attribute { clixon_xpath_parselval.intval = A_ATTRIBUTE; return AXISNAME; }
|
||||||
|
<TOKEN>child { clixon_xpath_parselval.intval = A_CHILD; return AXISNAME; }
|
||||||
|
<TOKEN>descendant { clixon_xpath_parselval.intval = A_DESCENDANT; return AXISNAME; }
|
||||||
|
<TOKEN>descendant-or-self { clixon_xpath_parselval.intval = A_DESCENDANT_OR_SELF; return AXISNAME; }
|
||||||
|
<TOKEN>following { clixon_xpath_parselval.intval = A_FOLLOWING; return AXISNAME; }
|
||||||
|
<TOKEN>following-sibling { clixon_xpath_parselval.intval = A_FOLLOWING_SIBLING; return AXISNAME; }
|
||||||
|
<TOKEN>namespace { clixon_xpath_parselval.intval = A_NAMESPACE; return AXISNAME; }
|
||||||
|
<TOKEN>parent { clixon_xpath_parselval.intval = A_PARENT; return AXISNAME; }
|
||||||
|
<TOKEN>preceding { clixon_xpath_parselval.intval = A_PRECEEDING; return AXISNAME; }
|
||||||
|
<TOKEN>preceding-sibling { clixon_xpath_parselval.intval = A_PRECEEDING_SIBLING; return AXISNAME; }
|
||||||
|
<TOKEN>self { clixon_xpath_parselval.intval = A_SELF; return AXISNAME; }
|
||||||
|
<TOKEN>current { clixon_xpath_parselval.string = strdup(yytext); return NODETYPE; }
|
||||||
|
<TOKEN>comment { clixon_xpath_parselval.string = strdup(yytext); return NODETYPE; }
|
||||||
|
<TOKEN>text { clixon_xpath_parselval.string = strdup(yytext); return NODETYPE; }
|
||||||
|
<TOKEN>processing-instructions { clixon_xpath_parselval.string = strdup(yytext); return NODETYPE; }
|
||||||
|
<TOKEN>node { clixon_xpath_parselval.string = strdup(yytext); return NODETYPE; }
|
||||||
|
<TOKEN>\" { BEGIN(QLITERAL); return QUOTE; }
|
||||||
|
<TOKEN>\' { BEGIN(ALITERAL); return APOST; }
|
||||||
|
<TOKEN>\-?({integer}|{real}) { sscanf(yytext,"%lf",&clixon_xpath_parselval.dval); return NUMBER;}
|
||||||
|
<TOKEN>[0-9A-Za-z_\-]+ { clixon_xpath_parselval.string = strdup(yytext);
|
||||||
|
return NAME; /* rather be catch-all */
|
||||||
|
}
|
||||||
|
<TOKEN>. { fprintf(stderr,"LEXICAL ERROR\n"); return -1; }
|
||||||
|
<QLITERAL>\" { BEGIN(TOKEN); return QUOTE; }
|
||||||
|
<QLITERAL>. { clixon_xpath_parselval.string = strdup(yytext);
|
||||||
|
return CHAR;}
|
||||||
|
<ALITERAL>\' { BEGIN(TOKEN); return APOST; }
|
||||||
|
<ALITERAL>. { clixon_xpath_parselval.string = strdup(yytext);
|
||||||
|
return CHAR;}
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
|
||||||
|
/*! Initialize scanner.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xpath_scan_init(struct clicon_xpath_yacc_arg *xy)
|
||||||
|
{
|
||||||
|
BEGIN(TOKEN);
|
||||||
|
xy->xy_lexbuf = yy_scan_string (xy->xy_parse_string);
|
||||||
|
#if 1 /* XXX: just to use unput to avoid warning */
|
||||||
|
if (0)
|
||||||
|
yyunput(0, "");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* free buffers
|
||||||
|
* Even within Flex version 2.5 (this is assumed), freeing buffers is different.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
xpath_scan_exit(struct clicon_xpath_yacc_arg *xy)
|
||||||
|
{
|
||||||
|
yy_delete_buffer(xy->xy_lexbuf);
|
||||||
|
clixon_xpath_parselex_destroy(); /* modern */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
289
lib/src/clixon_xpath_parse.y
Normal file
289
lib/src/clixon_xpath_parse.y
Normal file
|
|
@ -0,0 +1,289 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
Copyright (C) 2009-2018 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 *****
|
||||||
|
|
||||||
|
* XPATH Parser
|
||||||
|
* From https://www.w3.org/TR/xpath-10/
|
||||||
|
* The primary syntactic construct in XPath is the expression.
|
||||||
|
* An expression matches the production Expr
|
||||||
|
* see https://www.w3.org/TR/xpath-10/#NT-Expr)
|
||||||
|
* Lexical structure is defined by ExprToken, see
|
||||||
|
* see https://www.w3.org/TR/xpath-10/#exprlex
|
||||||
|
*/
|
||||||
|
|
||||||
|
%start start
|
||||||
|
|
||||||
|
%union {
|
||||||
|
int intval;
|
||||||
|
double dval;
|
||||||
|
char *string;
|
||||||
|
void *stack; /* xpath_tree */
|
||||||
|
}
|
||||||
|
|
||||||
|
%token <intval> AXISNAME
|
||||||
|
%token <intval> LOGOP
|
||||||
|
%token <intval> ADDOP
|
||||||
|
%token <intval> RELOP
|
||||||
|
|
||||||
|
%token <dval> NUMBER
|
||||||
|
|
||||||
|
%token <string> X_EOF
|
||||||
|
%token <string> QUOTE
|
||||||
|
%token <string> APOST
|
||||||
|
%token <string> CHAR
|
||||||
|
%token <string> NAME
|
||||||
|
%token <string> NODETYPE
|
||||||
|
%token <string> DOUBLEDOT
|
||||||
|
%token <string> DOUBLECOLON
|
||||||
|
%token <string> DOUBLESLASH
|
||||||
|
%token <string> FUNCTIONNAME
|
||||||
|
|
||||||
|
%type <intval> axisspec
|
||||||
|
|
||||||
|
%type <string> string
|
||||||
|
%type <stack> expr
|
||||||
|
%type <stack> andexpr
|
||||||
|
%type <stack> relexpr
|
||||||
|
%type <stack> addexpr
|
||||||
|
%type <stack> unionexpr
|
||||||
|
%type <stack> pathexpr
|
||||||
|
%type <stack> locationpath
|
||||||
|
%type <stack> abslocpath
|
||||||
|
%type <stack> rellocpath
|
||||||
|
%type <stack> step
|
||||||
|
%type <stack> nodetest
|
||||||
|
%type <stack> predicates
|
||||||
|
%type <stack> primaryexpr
|
||||||
|
|
||||||
|
%lex-param {void *_xy} /* Add this argument to parse() and lex() function */
|
||||||
|
%parse-param {void *_xy}
|
||||||
|
|
||||||
|
%{
|
||||||
|
/* Here starts user C-code */
|
||||||
|
|
||||||
|
/* typecast macro */
|
||||||
|
#define _XY ((struct clicon_xpath_yacc_arg *)_xy)
|
||||||
|
|
||||||
|
#define _YYERROR(msg) {clicon_err(OE_XML, 0, "YYERROR %s '%s' %d", (msg), clixon_xpath_parsetext, _XY->xy_linenum); YYERROR;}
|
||||||
|
|
||||||
|
/* add _yy to error paramaters */
|
||||||
|
#define YY_(msgid) msgid
|
||||||
|
|
||||||
|
#include "clixon_config.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fnmatch.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
|
||||||
|
#include <cligen/cligen.h>
|
||||||
|
|
||||||
|
#include "clixon_err.h"
|
||||||
|
#include "clixon_log.h"
|
||||||
|
#include "clixon_queue.h"
|
||||||
|
#include "clixon_string.h"
|
||||||
|
#include "clixon_hash.h"
|
||||||
|
#include "clixon_handle.h"
|
||||||
|
#include "clixon_yang.h"
|
||||||
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_xpath_ctx.h"
|
||||||
|
#include "clixon_xpath.h"
|
||||||
|
|
||||||
|
#include "clixon_xpath_parse.h"
|
||||||
|
|
||||||
|
extern int clixon_xpath_parseget_lineno (void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
also called from yacc generated code *
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
clixon_xpath_parseerror(void *_xy,
|
||||||
|
char *s)
|
||||||
|
{
|
||||||
|
clicon_err(OE_XML, 0, "%s on line %d: %s at or before: '%s'",
|
||||||
|
_XY->xy_name,
|
||||||
|
_XY->xy_linenum ,
|
||||||
|
s,
|
||||||
|
clixon_xpath_parsetext);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xpath_parse_init(struct clicon_xpath_yacc_arg *xy)
|
||||||
|
{
|
||||||
|
// clicon_debug_init(2, NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xpath_parse_exit(struct clicon_xpath_yacc_arg *xy)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static xpath_tree *
|
||||||
|
xp_new(enum xp_type type,
|
||||||
|
int i0,
|
||||||
|
double d0,
|
||||||
|
char *s0,
|
||||||
|
char *s1,
|
||||||
|
xpath_tree *c0,
|
||||||
|
xpath_tree *c1)
|
||||||
|
{
|
||||||
|
xpath_tree *xs = NULL;
|
||||||
|
|
||||||
|
if ((xs = malloc(sizeof(xpath_tree))) == NULL){
|
||||||
|
clicon_err(OE_XML, errno, "malloc");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
memset(xs, 0, sizeof(*xs));
|
||||||
|
xs->xs_type = type;
|
||||||
|
xs->xs_int = i0;
|
||||||
|
xs->xs_double = d0;
|
||||||
|
xs->xs_s0 = s0;
|
||||||
|
xs->xs_s1 = s1;
|
||||||
|
xs->xs_c0 = c0;
|
||||||
|
xs->xs_c1 = c1;
|
||||||
|
done:
|
||||||
|
return xs;
|
||||||
|
}
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
|
||||||
|
start : expr X_EOF { _XY->xy_top=$1;clicon_debug(1,"start->expr"); YYACCEPT; }
|
||||||
|
| locationpath X_EOF { _XY->xy_top=$1;clicon_debug(1,"start->locationpath"); YYACCEPT; }
|
||||||
|
;
|
||||||
|
|
||||||
|
expr : expr LOGOP andexpr { $$=xp_new(XP_EXP,$2,0.0,NULL,NULL,$1, $3);clicon_debug(1,"expr->expr or andexpr"); }
|
||||||
|
| andexpr { $$=xp_new(XP_EXP,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"expr-> andexpr"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
andexpr : andexpr LOGOP relexpr { $$=xp_new(XP_AND,$2,0.0,NULL,NULL,$1, $3);clicon_debug(1,"andexpr-> andexpr and relexpr"); }
|
||||||
|
| relexpr { $$=xp_new(XP_AND,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"andexpr-> relexpr"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
relexpr : relexpr RELOP addexpr { $$=xp_new(XP_RELEX,$2,0.0,NULL,NULL,$1, $3);clicon_debug(1,"relexpr-> relexpr relop addexpr"); }
|
||||||
|
| addexpr { $$=xp_new(XP_RELEX,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"relexpr-> addexpr"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
addexpr : addexpr ADDOP unionexpr { $$=xp_new(XP_ADD,$2,0.0,NULL,NULL,$1, $3);clicon_debug(1,"addexpr-> addexpr ADDOP unionexpr"); }
|
||||||
|
| unionexpr { $$=xp_new(XP_ADD,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"addexpr-> unionexpr"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
/* node-set */
|
||||||
|
unionexpr : unionexpr '|' pathexpr { $$=xp_new(XP_UNION,A_NAN,0.0,NULL,NULL,$1, $3);clicon_debug(1,"unionexpr-> unionexpr | pathexpr"); }
|
||||||
|
| pathexpr { $$=xp_new(XP_UNION,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"unionexpr-> pathexpr"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
pathexpr : locationpath { $$=xp_new(XP_PATHEXPR,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"pathexpr-> locationpath"); }
|
||||||
|
| primaryexpr { $$=xp_new(XP_PATHEXPR,A_NAN,0.0,NULL,NULL,$1, NULL);clicon_debug(1,"pathexpr-> primaryexpr"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
/* location path returns a node-set */
|
||||||
|
locationpath : rellocpath { $$=xp_new(XP_LOCPATH,A_NAN,0.0,NULL,NULL,$1, NULL); clicon_debug(1,"locationpath-> rellocpath"); }
|
||||||
|
| abslocpath { $$=xp_new(XP_LOCPATH,A_NAN,0.0,NULL,NULL,$1, NULL); clicon_debug(1,"locationpath-> abslocpath"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
abslocpath : '/' { $$=xp_new(XP_ABSPATH,A_ROOT,0.0,NULL,NULL,NULL, NULL);clicon_debug(1,"abslocpath-> /"); }
|
||||||
|
| '/' rellocpath { $$=xp_new(XP_ABSPATH,A_ROOT,0.0,NULL,NULL,$2, NULL);clicon_debug(1,"abslocpath->/ rellocpath");}
|
||||||
|
/* // is short for /descendant-or-self::node()/ */
|
||||||
|
| DOUBLESLASH rellocpath {$$=xp_new(XP_ABSPATH,A_DESCENDANT_OR_SELF,0.0,NULL,NULL,$2, NULL); clicon_debug(1,"abslocpath-> // rellocpath"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
rellocpath : step { $$=xp_new(XP_RELLOCPATH,A_NAN,0.0,NULL,NULL,$1, NULL); clicon_debug(1,"rellocpath-> step"); }
|
||||||
|
| rellocpath '/' step { $$=xp_new(XP_RELLOCPATH,A_NAN,0.0,NULL,NULL,$1, $3);clicon_debug(1,"rellocpath-> rellocpath / step"); }
|
||||||
|
| rellocpath DOUBLESLASH step { $$=xp_new(XP_RELLOCPATH,A_DESCENDANT_OR_SELF,0.0,NULL,NULL,$1, $3); clicon_debug(1,"rellocpath-> rellocpath // step"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
step : axisspec nodetest predicates {$$=xp_new(XP_STEP,$1,0.0, NULL, NULL, $2, $3);clicon_debug(1,"step->axisspec(%d) nodetest", $1); }
|
||||||
|
| '.' { $$=xp_new(XP_STEP,A_SELF, 0.0,NULL, NULL, NULL, NULL); clicon_debug(1,"step-> ."); }
|
||||||
|
| DOUBLEDOT { $$=xp_new(XP_STEP, A_PARENT, 0.0,NULL, NULL, NULL, NULL); clicon_debug(1,"step-> .."); }
|
||||||
|
;
|
||||||
|
|
||||||
|
axisspec : AXISNAME DOUBLECOLON { clicon_debug(1,"axisspec-> AXISNAME(%d) ::", $1); $$=$1;}
|
||||||
|
| '@' { $$=A_ATTRIBUTE; clicon_debug(1,"axisspec-> @"); }
|
||||||
|
| { clicon_debug(1,"axisspec-> "); $$=A_CHILD;}
|
||||||
|
;
|
||||||
|
|
||||||
|
nodetest : '*' { $$=xp_new(XP_NODE,A_NAN,0.0, NULL, NULL, NULL, NULL); clicon_debug(1,"nodetest-> *"); }
|
||||||
|
| NAME { $$=xp_new(XP_NODE,A_NAN,0.0, NULL, $1, NULL, NULL); clicon_debug(1,"nodetest-> name(%s)",$1); }
|
||||||
|
| NAME ':' NAME { $$=xp_new(XP_NODE,A_NAN,0.0, $1, $3, NULL, NULL);clicon_debug(1,"nodetest-> name(%s) : name(%s)", $1, $3); }
|
||||||
|
| NAME ':' '*' { $$=xp_new(XP_NODE,A_NAN,0.0, $1, NULL, NULL, NULL);clicon_debug(1,"nodetest-> name(%s) : *", $1); }
|
||||||
|
| NODETYPE '(' ')' { $$=xp_new(XP_NODE_FN,A_NAN,0.0, $1, NULL, NULL, NULL); clicon_debug(1,"nodetest-> nodetype()"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
/* evaluates to boolean */
|
||||||
|
predicates : predicates '[' expr ']' { $$=xp_new(XP_PRED,A_NAN,0.0, NULL, NULL, $1, $3); clicon_debug(1,"predicates-> [ expr ]"); }
|
||||||
|
| { $$=xp_new(XP_PRED,A_NAN,0.0, NULL, NULL, NULL, NULL); clicon_debug(1,"predicates->"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
primaryexpr : '(' expr ')' { $$=xp_new(XP_PRI0,A_NAN,0.0, NULL, NULL, $2, NULL); clicon_debug(1,"primaryexpr-> ( expr )"); }
|
||||||
|
| NUMBER { $$=xp_new(XP_PRIME_NR,A_NAN, $1, NULL, NULL, NULL, NULL);clicon_debug(1,"primaryexpr-> NUMBER(%lf)", $1); }
|
||||||
|
| QUOTE string QUOTE { $$=xp_new(XP_PRIME_STR,A_NAN,0.0, $2, NULL, NULL, NULL);clicon_debug(1,"primaryexpr-> \" string \""); }
|
||||||
|
| QUOTE QUOTE { $$=xp_new(XP_PRIME_STR,A_NAN,0.0, NULL, NULL, NULL, NULL);clicon_debug(1,"primaryexpr-> \" \""); }
|
||||||
|
| APOST string APOST { $$=xp_new(XP_PRIME_STR,A_NAN,0.0, $2, NULL, NULL, NULL);clicon_debug(1,"primaryexpr-> ' string '"); }
|
||||||
|
| APOST APOST { $$=xp_new(XP_PRIME_STR,A_NAN,0.0, NULL, NULL, NULL, NULL);clicon_debug(1,"primaryexpr-> ' '"); }
|
||||||
|
| FUNCTIONNAME '(' ')' { $$=xp_new(XP_PRIME_FN,A_NAN,0.0, $1, NULL, NULL, NULL);clicon_debug(1,"primaryexpr-> functionname ( arguments )"); }
|
||||||
|
;
|
||||||
|
|
||||||
|
/* XXX Adding this between FUNCTIONNAME() breaks parser,..
|
||||||
|
arguments : arguments expr { clicon_debug(1,"arguments-> arguments expr"); }
|
||||||
|
| { clicon_debug(1,"arguments-> "); }
|
||||||
|
;
|
||||||
|
*/
|
||||||
|
string : string CHAR {
|
||||||
|
int len = strlen($1);
|
||||||
|
$$ = realloc($1, len+strlen($2) + 1);
|
||||||
|
sprintf($$+len, "%s", $2);
|
||||||
|
free($2);
|
||||||
|
clicon_debug(1,"string-> string CHAR");
|
||||||
|
}
|
||||||
|
| CHAR { clicon_debug(1,"string-> "); }
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
|
@ -35,54 +35,12 @@
|
||||||
* NOTE: there is a main function at the end of this file where you can test out
|
* NOTE: there is a main function at the end of this file where you can test out
|
||||||
* different xpath expressions.
|
* different xpath expressions.
|
||||||
* Look at the end of the file for a test unit program
|
* Look at the end of the file for a test unit program
|
||||||
*/
|
|
||||||
/*
|
|
||||||
See https://www.w3.org/TR/xpath/
|
|
||||||
|
|
||||||
Implementation of a limited xslt xpath syntax. Some examples. Given the following
|
|
||||||
xml tree:
|
|
||||||
<aaa>
|
|
||||||
<bbb x="hello"><ccc>42</ccc></bbb>
|
|
||||||
<bbb x="bye"><ccc>99</ccc></bbb>
|
|
||||||
<ddd><ccc>22</ccc></ddd>
|
|
||||||
</aaa>
|
|
||||||
|
|
||||||
With the following xpath examples. There are some diffs and many limitations compared
|
|
||||||
to the xml standards:
|
|
||||||
/ whole tree <aaa>...</aaa>
|
|
||||||
/bbb
|
|
||||||
/aaa/bbb <bbb x="hello"><ccc>42</ccc></bbb>
|
|
||||||
<bbb x="bye"><ccc>99</ccc></bbb>
|
|
||||||
//bbb as above
|
|
||||||
//b?b as above
|
|
||||||
//b\* as above
|
|
||||||
//b\*\/ccc <ccc>42</ccc>
|
|
||||||
<ccc>99</ccc>
|
|
||||||
//\*\/ccc <ccc>42</ccc>
|
|
||||||
<ccc>99</ccc>
|
|
||||||
<ccc>22</ccc>
|
|
||||||
-- //bbb@x x="hello"
|
|
||||||
//bbb[@x] <bbb x="hello"><ccc>42</ccc></bbb>
|
|
||||||
<bbb x="bye"><ccc>99</ccc></bbb>
|
|
||||||
//bbb[@x=hello] <bbb x="hello"><ccc>42</ccc></bbb>
|
|
||||||
//bbb[@x="hello"] as above
|
|
||||||
//bbb[0] <bbb x="hello"><ccc>42</ccc></bbb>
|
|
||||||
//bbb[ccc=99] <bbb x="bye"><ccc>99</ccc></bbb>
|
|
||||||
--- //\*\/[ccc=99] same as above
|
|
||||||
'//bbb | //ddd' <bbb><ccc>42</ccc></bbb>
|
|
||||||
<bbb x="hello"><ccc>99</ccc></bbb>
|
|
||||||
<ddd><ccc>22</ccc></ddd> (NB spaces)
|
|
||||||
etc
|
|
||||||
For xpath v1.0 see http://www.w3.org/TR/xpath/
|
|
||||||
record[name=c][time=d]
|
|
||||||
in
|
|
||||||
<record>
|
|
||||||
<name>c</name>
|
|
||||||
<time>d</time>
|
|
||||||
<userid>45654df4-2292-45d3-9ca5-ee72452568a8</userid>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
|
The code is implemented according to XPATH 1.0:
|
||||||
|
https://www.w3.org/TR/xpath-10/
|
||||||
|
|
||||||
|
The primary syntactic construct in XPath is the expression. An expression matches
|
||||||
|
the production Expr (see https://www.w3.org/TR/xpath-10/#NT-Expr)
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
@ -95,6 +53,7 @@ in
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
/* cligen */
|
/* cligen */
|
||||||
#include <cligen/cligen.h>
|
#include <cligen/cligen.h>
|
||||||
|
|
@ -108,14 +67,18 @@ in
|
||||||
#include "clixon_handle.h"
|
#include "clixon_handle.h"
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
|
#include "clixon_xpath_ctx.h"
|
||||||
|
#include "clixon_xpath.h"
|
||||||
#include "clixon_xsl.h"
|
#include "clixon_xsl.h"
|
||||||
|
|
||||||
|
|
||||||
/* Constants */
|
/* Constants */
|
||||||
#define XPATH_VEC_START 128
|
#define XPATH_VEC_START 128
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Types
|
* Types
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct searchvec{
|
struct searchvec{
|
||||||
cxobj **sv_v0; /* here is result */
|
cxobj **sv_v0; /* here is result */
|
||||||
int sv_v0len;
|
int sv_v0len;
|
||||||
|
|
@ -127,13 +90,22 @@ typedef struct searchvec searchvec;
|
||||||
|
|
||||||
/* Local types
|
/* Local types
|
||||||
*/
|
*/
|
||||||
enum axis_type{
|
|
||||||
A_SELF,
|
struct xpath_predicate{
|
||||||
A_CHILD,
|
struct xpath_predicate *xp_next;
|
||||||
A_PARENT,
|
char *xp_expr;
|
||||||
A_ROOT,
|
};
|
||||||
A_ANCESTOR,
|
|
||||||
A_DESCENDANT_OR_SELF, /* actually descendant-or-self */
|
/* XPATH Axis according to https://www.w3.org/TR/xpath-10/#NT-Step
|
||||||
|
* Axis ::= AxisSpecifier NodeTest Predicate*
|
||||||
|
* Eg "child::
|
||||||
|
*/
|
||||||
|
struct xpath_element{
|
||||||
|
struct xpath_element *xe_next;
|
||||||
|
enum axis_type xe_type;
|
||||||
|
char *xe_prefix; /* eg for namespaces */
|
||||||
|
char *xe_str; /* eg for child */
|
||||||
|
struct xpath_predicate *xe_predicate; /* eg within [] */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Mapping between axis type string <--> int */
|
/* Mapping between axis type string <--> int */
|
||||||
|
|
@ -147,23 +119,12 @@ static const map_str2int axismap[] = {
|
||||||
{NULL, -1}
|
{NULL, -1}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct xpath_predicate{
|
|
||||||
struct xpath_predicate *xp_next;
|
|
||||||
char *xp_expr;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct xpath_element{
|
|
||||||
struct xpath_element *xe_next;
|
|
||||||
enum axis_type xe_type;
|
|
||||||
char *xe_prefix; /* eg for namespaces */
|
|
||||||
char *xe_str; /* eg for child */
|
|
||||||
struct xpath_predicate *xe_predicate; /* eg within [] */
|
|
||||||
};
|
|
||||||
|
|
||||||
static int xpath_split(char *xpathstr, char **pathexpr);
|
static int xpath_split(char *xpathstr, char **pathexpr);
|
||||||
|
|
||||||
|
/*! Print xpath structure for debug */
|
||||||
static int
|
static int
|
||||||
xpath_print(FILE *f, struct xpath_element *xplist)
|
xpath_print(FILE *f,
|
||||||
|
struct xpath_element *xplist)
|
||||||
{
|
{
|
||||||
struct xpath_element *xe;
|
struct xpath_element *xe;
|
||||||
struct xpath_predicate *xp;
|
struct xpath_predicate *xp;
|
||||||
|
|
@ -217,6 +178,11 @@ xpath_parse_predicate(struct xpath_element *xe,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! XPATH parse, create new child element
|
||||||
|
* @param[in] atype Axis type, see https://www.w3.org/TR/xpath-10/#axes
|
||||||
|
* @param[in] str
|
||||||
|
* @param[out] xpnext
|
||||||
|
*/
|
||||||
static int
|
static int
|
||||||
xpath_element_new(enum axis_type atype,
|
xpath_element_new(enum axis_type atype,
|
||||||
char *str,
|
char *str,
|
||||||
|
|
@ -309,8 +275,17 @@ xpath_free(struct xpath_element *xplist)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*! Parse xpath to xpath_element structure
|
||||||
* // is short for /descendant-or-self::node()/
|
|
||||||
|
*
|
||||||
|
* [1] LocationPath ::= RelativeLocationPath
|
||||||
|
* | AbsoluteLocationPath
|
||||||
|
* [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
|
||||||
|
* | AbbreviatedAbsoluteLocationPath
|
||||||
|
* [3] RelativeLocationPath ::= Step
|
||||||
|
| RelativeLocationPath '/' Step
|
||||||
|
| AbbreviatedRelativeLocationPath
|
||||||
|
* @see https://www.w3.org/TR/xpath-10/#NT-LocationPath
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
xpath_parse(char *xpath,
|
xpath_parse(char *xpath,
|
||||||
|
|
@ -355,6 +330,7 @@ xpath_parse(char *xpath,
|
||||||
}
|
}
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
|
/* Iterate through steps (s), see https://www.w3.org/TR/xpath-10/#NT-Step */
|
||||||
s = s0;
|
s = s0;
|
||||||
for (i=0; i<nvec; i++){
|
for (i=0; i<nvec; i++){
|
||||||
if ((i==0 && strcmp(s,"")==0)) /* Initial / or // */
|
if ((i==0 && strcmp(s,"")==0)) /* Initial / or // */
|
||||||
|
|
@ -364,21 +340,10 @@ xpath_parse(char *xpath,
|
||||||
else if (strncmp(s,"descendant-or-self::", strlen("descendant-or-self::"))==0){
|
else if (strncmp(s,"descendant-or-self::", strlen("descendant-or-self::"))==0){
|
||||||
xpath_element_new(A_DESCENDANT_OR_SELF, s+strlen("descendant-or-self::"), &xpnext);
|
xpath_element_new(A_DESCENDANT_OR_SELF, s+strlen("descendant-or-self::"), &xpnext);
|
||||||
}
|
}
|
||||||
#if 1
|
|
||||||
else if (strncmp(s,"..", strlen(".."))==0) /* abbreviatedstep */
|
else if (strncmp(s,"..", strlen(".."))==0) /* abbreviatedstep */
|
||||||
xpath_element_new(A_PARENT, s+strlen(".."), &xpnext);
|
xpath_element_new(A_PARENT, s+strlen(".."), &xpnext);
|
||||||
#else
|
|
||||||
else if (strncmp(s,"..", strlen(s))==0) /* abbreviatedstep */
|
|
||||||
xpath_element_new(A_PARENT, NULL, &xpnext);
|
|
||||||
#endif
|
|
||||||
#if 1 /* Problems with .[userid=1321] */
|
|
||||||
else if (strncmp(s,".", strlen("."))==0)
|
else if (strncmp(s,".", strlen("."))==0)
|
||||||
xpath_element_new(A_SELF, s+strlen("."), &xpnext);
|
xpath_element_new(A_SELF, s+strlen("."), &xpnext);
|
||||||
#else
|
|
||||||
else if (strncmp(s,".", strlen(s))==0) /* abbreviatedstep */
|
|
||||||
xpath_element_new(A_SELF, NULL, &xpnext);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
else if (strncmp(s,"self::", strlen("self::"))==0)
|
else if (strncmp(s,"self::", strlen("self::"))==0)
|
||||||
xpath_element_new(A_SELF, s+strlen("self::"), &xpnext);
|
xpath_element_new(A_SELF, s+strlen("self::"), &xpnext);
|
||||||
|
|
||||||
|
|
@ -406,17 +371,15 @@ xpath_parse(char *xpath,
|
||||||
* The xv_* arguments are filled in nodes found earlier.
|
* The xv_* arguments are filled in nodes found earlier.
|
||||||
* args:
|
* args:
|
||||||
* @param[in] xn_parent Base XML object
|
* @param[in] xn_parent Base XML object
|
||||||
* @param[in] name shell wildcard pattern to match with node name
|
* @param[in] pattern Shell wildcard pattern to match with node name
|
||||||
* @param[in] node_type CX_ELMNT, CX_ATTR or CX_BODY
|
* @param[in] node_type CX_ELMNT, CX_ATTR or CX_BODY
|
||||||
* @param[in,out] vec1 internal buffers with results
|
* @param[in,out] vec0 Internal buffers with results
|
||||||
* @param[in,out] vec0 internal buffers with results
|
* @param[in,out] vec0len Internal buffers with length of vec0
|
||||||
* @param[in,out] vec_len internal buffers with length of vec0,vec1
|
|
||||||
* @param[in,out] vec_max internal buffers with max of vec0,vec1
|
|
||||||
* returns:
|
* returns:
|
||||||
* 0 on OK, -1 on error
|
* 0 on OK, -1 on error
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
recursive_find(cxobj *xn,
|
xpath_recursive_find(cxobj *xn,
|
||||||
char *pattern,
|
char *pattern,
|
||||||
int node_type,
|
int node_type,
|
||||||
uint16_t flags,
|
uint16_t flags,
|
||||||
|
|
@ -439,7 +402,7 @@ recursive_find(cxobj *xn,
|
||||||
goto done;
|
goto done;
|
||||||
// continue; /* Dont go deeper */
|
// continue; /* Dont go deeper */
|
||||||
}
|
}
|
||||||
if (recursive_find(xsub, pattern, node_type, flags, &vec, &veclen) < 0)
|
if (xpath_recursive_find(xsub, pattern, node_type, flags, &vec, &veclen) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
retval = 0;
|
retval = 0;
|
||||||
|
|
@ -695,7 +658,7 @@ xpath_find(cxobj *xcur,
|
||||||
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, flags, &vec1, &vec1len) < 0)
|
if (xpath_recursive_find(xv, xe->xe_str, CX_ELMNT, flags, &vec1, &vec1len) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -738,7 +701,6 @@ xpath_find(cxobj *xcur,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (xp = xe->xe_predicate; xp; xp = xp->xp_next){
|
for (xp = xe->xe_predicate; xp; xp = xp->xp_next){
|
||||||
if (xpath_expr(xcur, xp->xp_expr, flags, &vec0, &vec0len) < 0)
|
if (xpath_expr(xcur, xp->xp_expr, flags, &vec0, &vec0len) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -798,6 +760,7 @@ xpath_split(char *xpathstr,
|
||||||
* @param[in] flags if != 0, only match xml nodes matching flags
|
* @param[in] flags if != 0, only match xml nodes matching flags
|
||||||
* @param[out] vec2 Result XML node vector
|
* @param[out] vec2 Result XML node vector
|
||||||
* @param[out] vec2len Length of result vector.
|
* @param[out] vec2len Length of result vector.
|
||||||
|
* @see https://www.w3.org/TR/xpath-10/#NT-LocationPath
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
xpath_exec(cxobj *xcur,
|
xpath_exec(cxobj *xcur,
|
||||||
|
|
@ -831,14 +794,20 @@ xpath_exec(cxobj *xcur,
|
||||||
* @param[in] xcur xml-tree where to search
|
* @param[in] xcur xml-tree where to search
|
||||||
* @param[in] xpath string with XPATH syntax
|
* @param[in] xpath string with XPATH syntax
|
||||||
* @param[in] flags if != 0, only match xml nodes matching flags
|
* @param[in] flags if != 0, only match xml nodes matching flags
|
||||||
* @param[in] vec1 vector of XML trees
|
* @param[out] vec1 vector of XML trees
|
||||||
* @param[in] vec1len length of XML trees
|
* @param[out] vec1len length of XML trees
|
||||||
* For example: xpath = //a | //b.
|
* For example: xpath = //a | //b.
|
||||||
* xpath_first+ splits xpath up in several subcalls
|
* xpath_first+ splits xpath up in several subcalls
|
||||||
* (eg xpath=//a and xpath=//b) and collects the results.
|
* (eg xpath=//a and xpath=//b) and collects the results.
|
||||||
* Note: if a match is found in both, two (or more) same results will be
|
* Note: if a match is found in both, two (or more) same results will be
|
||||||
* returned.
|
* returned.
|
||||||
* Note, this could be 'folded' into xpath1 but I judged it too complex.
|
* Note, this could be 'folded' into xpath1 but I judged it too complex.
|
||||||
|
* @see https://www.w3.org/TR/xpath-10/#NT-Expr
|
||||||
|
* An 'Expr' is composed of compositions of and, or, =, +, -, down to:
|
||||||
|
* PathExpr ::= LocationPath
|
||||||
|
* | FilterExpr
|
||||||
|
* | FilterExpr '/' RelativeLocationPath
|
||||||
|
* | FilterExpr '//' RelativeLocationPath
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
xpath_choice(cxobj *xcur,
|
xpath_choice(cxobj *xcur,
|
||||||
|
|
@ -848,7 +817,7 @@ xpath_choice(cxobj *xcur,
|
||||||
size_t *vec1len)
|
size_t *vec1len)
|
||||||
{
|
{
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
char *s0;
|
char *s0 = NULL;
|
||||||
char *s1;
|
char *s1;
|
||||||
char *s2;
|
char *s2;
|
||||||
char *xpath;
|
char *xpath;
|
||||||
|
|
@ -1020,7 +989,7 @@ xpath_each(cxobj *xcur,
|
||||||
/*! A restricted xpath that returns a vector of matches
|
/*! A restricted xpath that returns a vector of matches
|
||||||
*
|
*
|
||||||
* See xpath1() on details for subset
|
* See xpath1() on details for subset
|
||||||
. * @param[in] xcur xml-tree where to search
|
* @param[in] xcur xml-tree where to search
|
||||||
* @param[in] xpath string with XPATH syntax
|
* @param[in] xpath string with XPATH syntax
|
||||||
* @param[out] vec vector of xml-trees. Vector must be free():d after use
|
* @param[out] vec vector of xml-trees. Vector must be free():d after use
|
||||||
* @param[out] veclen returns length of vector in return value
|
* @param[out] veclen returns length of vector in return value
|
||||||
|
|
@ -1052,7 +1021,7 @@ xpath_vec(cxobj *xcur,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
size_t len;
|
size_t len;
|
||||||
char *xpath;
|
char *xpath = NULL;
|
||||||
|
|
||||||
va_start(ap, veclen);
|
va_start(ap, veclen);
|
||||||
len = vsnprintf(NULL, 0, format, ap);
|
len = vsnprintf(NULL, 0, format, ap);
|
||||||
|
|
@ -1079,6 +1048,7 @@ xpath_vec(cxobj *xcur,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* A restricted xpath that returns a vector of matches (only nodes marked with flags)
|
/* A restricted xpath that returns a vector of matches (only nodes marked with flags)
|
||||||
* @param[in] xcur xml-tree where to search
|
* @param[in] xcur xml-tree where to search
|
||||||
* @param[in] xpath string with XPATH syntax
|
* @param[in] xpath string with XPATH syntax
|
||||||
|
|
@ -1140,96 +1110,3 @@ xpath_vec_flag(cxobj *xcur,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Turn this on to get an xpath test program
|
|
||||||
* Usage: xpath [<xpath>]
|
|
||||||
* read xpath on first line and xml on rest of lines from input
|
|
||||||
* Example compile:
|
|
||||||
gcc -g -o xpath -I. -I../clixon ./clixon_xsl.c -lclixon -lcligen
|
|
||||||
* Example run:
|
|
||||||
echo "a\n<a><b/></a>" | xpath
|
|
||||||
*/
|
|
||||||
#if 0 /* Test program */
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
usage(char *argv0)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "usage:%s <xml file name>.\n\tInput on stdin\n", argv0);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
int retval = -1;
|
|
||||||
int i;
|
|
||||||
cxobj **xv;
|
|
||||||
cxobj *x;
|
|
||||||
cxobj *xn;
|
|
||||||
size_t xlen = 0;
|
|
||||||
int c;
|
|
||||||
int len;
|
|
||||||
char *buf = NULL;
|
|
||||||
char *filename;
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
if (argc != 2){
|
|
||||||
usage(argv[0]);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
filename = argv[1];
|
|
||||||
if ((fd = open(filename, O_RDONLY)) < 0){
|
|
||||||
clicon_err(OE_UNIX, errno, "open(%s)", filename);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
/* Read xpath */
|
|
||||||
len = 1024; /* any number is fine */
|
|
||||||
if ((buf = malloc(len)) == NULL){
|
|
||||||
perror("pt_file malloc");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
memset(buf, 0, len);
|
|
||||||
i = 0;
|
|
||||||
while (1){ /* read the whole file */
|
|
||||||
if ((c = fgetc(stdin)) == EOF)
|
|
||||||
return -1;
|
|
||||||
if (c == '\n')
|
|
||||||
break;
|
|
||||||
if (len==i){
|
|
||||||
if ((buf = realloc(buf, 2*len)) == NULL){
|
|
||||||
fprintf(stderr, "%s: realloc: %s\n", __FUNCTION__, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
memset(buf+len, 0, len);
|
|
||||||
len *= 2;
|
|
||||||
}
|
|
||||||
buf[i++] = (char)(c&0xff);
|
|
||||||
}
|
|
||||||
x = NULL;
|
|
||||||
if (xml_parse_file(fd, "</clicon>", NULL, &x) < 0){
|
|
||||||
fprintf(stderr, "Error: parsing: %s\n", clicon_err_reason);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
close (fd);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
if (xpath_vec(x, "%s", &xv, &xlen, buf) < 0)
|
|
||||||
return -1;
|
|
||||||
if (xv){
|
|
||||||
for (i=0; i<xlen; i++){
|
|
||||||
xn = xv[i];
|
|
||||||
fprintf(stdout, "[%d]:\n", i);
|
|
||||||
clicon_xml2file(stdout, xn, 0, 1);
|
|
||||||
}
|
|
||||||
free(xv);
|
|
||||||
}
|
|
||||||
if (x)
|
|
||||||
xml_free(x);
|
|
||||||
retval = 0;
|
|
||||||
done:
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* Test program */
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ err(){
|
||||||
echo -e "\e[0m"
|
echo -e "\e[0m"
|
||||||
echo "$ret"| od -t c > $dir/clixon-ret
|
echo "$ret"| od -t c > $dir/clixon-ret
|
||||||
echo "$expect"| od -t c > $dir/clixon-expect
|
echo "$expect"| od -t c > $dir/clixon-expect
|
||||||
diff $dir/clixon-ret $dir/clixon-expect
|
diff $dir/clixon-expect $dir/clixon-ret
|
||||||
|
|
||||||
exit $testnr
|
exit $testnr
|
||||||
}
|
}
|
||||||
|
|
|
||||||
151
test/test_xpath.sh
Executable file
151
test/test_xpath.sh
Executable file
|
|
@ -0,0 +1,151 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Test: XPATH tests
|
||||||
|
PROG=../lib/src/clixon_util_xpath
|
||||||
|
|
||||||
|
# include err() and new() functions and creates $dir
|
||||||
|
. ./lib.sh
|
||||||
|
|
||||||
|
# XML file (alt provide it in stdin after xpath)
|
||||||
|
xml=$dir/xml.xml
|
||||||
|
xml2=$dir/xml2.xml
|
||||||
|
|
||||||
|
cat <<EOF > $xml
|
||||||
|
<aaa>
|
||||||
|
<bbb x="hello"><ccc>42</ccc></bbb>
|
||||||
|
<bbb x="bye"><ccc>99</ccc></bbb>
|
||||||
|
<ddd><ccc>22</ccc></ddd>
|
||||||
|
</aaa>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat <<EOF > $xml2
|
||||||
|
<if:interfaces>
|
||||||
|
<if:interface>
|
||||||
|
<if:name>e0</if:name>
|
||||||
|
<ip:ipv6>
|
||||||
|
<ip:enabled>true</ip:enabled>
|
||||||
|
</ip:ipv6>
|
||||||
|
</if:interface>
|
||||||
|
</if:interfaces>
|
||||||
|
<rt:name>e0</rt:name>
|
||||||
|
<address-family>myfamily</address-family>
|
||||||
|
<aaa>
|
||||||
|
<rt:address-family>v6ur:ipv6-unicast</rt:address-family>
|
||||||
|
<name>foo</name>
|
||||||
|
<bbb>
|
||||||
|
<routing>
|
||||||
|
<ribs>
|
||||||
|
<rib>
|
||||||
|
<name>bar</name>
|
||||||
|
<address-family>myfamily</address-family>
|
||||||
|
</rib>
|
||||||
|
</ribs>
|
||||||
|
</routing>
|
||||||
|
<max-rtr-adv-interval>22</max-rtr-adv-interval>
|
||||||
|
<valid-lifetime>99</valid-lifetime>
|
||||||
|
<connection-type>responder-only</connection-type>
|
||||||
|
<type>rt:static</type>
|
||||||
|
<rib-name>bar</rib-name>
|
||||||
|
<here>0</here>
|
||||||
|
<here2><here/></here2>
|
||||||
|
<ifType>ethernet</ifType>
|
||||||
|
<ifMTU>1500</ifMTU>
|
||||||
|
</bbb>
|
||||||
|
</aaa>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
new "xpath /"
|
||||||
|
expecteof "$PROG -f $xml -p /" 0 "" "^nodeset:0:<aaa><bbb x=\"hello\"><ccc>42</ccc></bbb><bbb x=\"bye\"><ccc>99</ccc></bbb><ddd><ccc>22</ccc></ddd></aaa>$"
|
||||||
|
|
||||||
|
new "xpath /aaa"
|
||||||
|
expecteof "$PROG -f $xml -p /aaa" 0 "" "^nodeset:0:<aaa><bbb x=\"hello\"><ccc>42</ccc></bbb><bbb x=\"bye\"><ccc>99</ccc></bbb><ddd><ccc>22</ccc></ddd></aaa>$"
|
||||||
|
|
||||||
|
new "xpath /bbb"
|
||||||
|
expecteof "$PROG -f $xml -p /bbb" 0 "" "^nodeset:$"
|
||||||
|
|
||||||
|
new "xpath /aaa/bbb"
|
||||||
|
expecteof "$PROG -f $xml -p /aaa/bbb" 0 "" "^0:<bbb x=\"hello\"><ccc>42</ccc></bbb>
|
||||||
|
1:<bbb x=\"bye\"><ccc>99</ccc></bbb>$"
|
||||||
|
|
||||||
|
new "xpath //bbb"
|
||||||
|
expecteof "$PROG -f $xml -p //bbb" 0 "" "0:<bbb x=\"hello\"><ccc>42</ccc></bbb>
|
||||||
|
1:<bbb x=\"bye\"><ccc>99</ccc></bbb>"
|
||||||
|
|
||||||
|
new "xpath //b?b"
|
||||||
|
#expecteof "$PROG -f $xml" 0 "//b?b" ""
|
||||||
|
|
||||||
|
new "xpath //b*"
|
||||||
|
#expecteof "$PROG -f $xml" 0 "//b*" ""
|
||||||
|
|
||||||
|
new "xpath //b*/ccc"
|
||||||
|
#expecteof "$PROG -f $xml" 0 "//b*/ccc" ""
|
||||||
|
|
||||||
|
new "xpath //bbb[0]"
|
||||||
|
expecteof "$PROG -f $xml -p //bbb[0]" 0 "" "^nodeset:0:<bbb x=\"hello\"><ccc>42</ccc></bbb>$"
|
||||||
|
|
||||||
|
new "xpath //bbb[ccc=99]"
|
||||||
|
expecteof "$PROG -f $xml -p //bbb[ccc=99]" 0 "" "^nodeset:0:<bbb x=\"bye\"><ccc>99</ccc></bbb>$"
|
||||||
|
|
||||||
|
new "xpath ../connection-type = 'responder-only'"
|
||||||
|
expecteof "$PROG -f $xml2 -p ../connection-type='responder-only' -i /aaa/bbb/here" 0 "" "^bool:true$"
|
||||||
|
|
||||||
|
new "xpath ../connection-type = 'no-responder'"
|
||||||
|
expecteof "$PROG -f $xml2 -p ../connection-type='no-responder' -i /aaa/bbb/here" 0 "" "^bool:false$"
|
||||||
|
|
||||||
|
new "xpath . <= 0.75 * ../max-rtr-adv-interval"
|
||||||
|
expecteof "$PROG -f $xml2 -i /aaa/bbb/here" 0 ". <= 0.75 * ../max-rtr-adv-interval" "^bool:true$"
|
||||||
|
|
||||||
|
new "xpath . > 0.75 * ../max-rtr-adv-interval"
|
||||||
|
expecteof "$PROG -f $xml2 -i /aaa/bbb/here" 0 ". > 0.75 * ../max-rtr-adv-interval" "^bool:false$"
|
||||||
|
|
||||||
|
new "xpath . <= ../valid-lifetime"
|
||||||
|
expecteof "$PROG -f $xml2 -i /aaa/bbb/here" 0 ". <= ../valid-lifetime" "^bool:true$"
|
||||||
|
|
||||||
|
new "xpath ../../rt:address-family = 'v6ur:ipv6-unicast'"
|
||||||
|
expecteof "$PROG -f $xml2 -i /aaa/bbb/here" 0 "../../rt:address-family = 'v6ur:ipv6-unicast'" "^bool:true$"
|
||||||
|
|
||||||
|
new "xpath ../../../rt:address-family = 'v6ur:ipv6-unicast'"
|
||||||
|
expecteof "$PROG -f $xml2 -i /aaa/bbb/here2/here" 0 "../../../rt:address-family = 'v6ur:ipv6-unicast'" "^bool:true$"
|
||||||
|
|
||||||
|
new "xpath /if:interfaces/if:interface[if:name=current()/rt:name]/ip:ipv6/ip:enabled='true'"
|
||||||
|
expecteof "$PROG -f $xml2" 0 "/if:interfaces/if:interface[if:name=current()/rt:name]/ip:ipv6/ip:enabled='true'" "^bool:true$"
|
||||||
|
|
||||||
|
new "xpath rt:address-family='v6ur:ipv6-unicast'"
|
||||||
|
expecteof "$PROG -f $xml2 -i /aaa" 0 "rt:address-family='v6ur:ipv6-unicast'" "^bool:true$"
|
||||||
|
|
||||||
|
new "xpath ../type='rt:static'"
|
||||||
|
expecteof "$PROG -f $xml2 -i /aaa/bbb/here" 0 "../type='rt:static'" "^bool:true$"
|
||||||
|
|
||||||
|
new "xpath rib-name != ../../name"
|
||||||
|
expecteof "$PROG -f $xml2 -i /aaa/bbb" 0 "rib-name != ../../name" "^bool:true$"
|
||||||
|
|
||||||
|
new "xpath routing/ribs/rib[name=current()/rib-name]/address-family=../../address-family"
|
||||||
|
expecteof "$PROG -f $xml2 -i /aaa/bbb" 0 "routing/ribs/rib[name=current()/rib-name]/address-family=../../address-family" "^bool:true$"
|
||||||
|
|
||||||
|
new "xpath ifType = \"ethernet\" or ifMTU = 1500"
|
||||||
|
expecteof "$PROG -f $xml2 -i /aaa/bbb" 0 "ifType = \"ethernet\" or ifMTU = 1500" "^bool:true$"
|
||||||
|
|
||||||
|
new "xpath ifType != \"ethernet\" or ifMTU = 1500"
|
||||||
|
expecteof "$PROG -f $xml2 -i /aaa/bbb" 0 "ifType != \"ethernet\" or ifMTU = 1500" "^bool:true$"
|
||||||
|
|
||||||
|
new "xpath ifType = \"ethernet\" or ifMTU = 1400"
|
||||||
|
expecteof "$PROG -f $xml2 -i /aaa/bbb" 0 "ifType = \"ethernet\" or ifMTU = 1400" "^bool:true$"
|
||||||
|
|
||||||
|
new "xpath ifType != \"ethernet\" or ifMTU = 1400"
|
||||||
|
expecteof "$PROG -f $xml2 -i /aaa/bbb" 0 "ifType != \"ethernet\" or ifMTU = 1400" "^bool:false$"
|
||||||
|
|
||||||
|
new "xpath ifType = \"ethernet\" and ifMTU = 1500"
|
||||||
|
expecteof "$PROG -f $xml2 -i /aaa/bbb" 0 "ifType = \"ethernet\" and ifMTU = 1500" "^bool:true$"
|
||||||
|
|
||||||
|
new "xpath ifType != \"ethernet\" and ifMTU = 1500"
|
||||||
|
expecteof "$PROG -f $xml2 -i /aaa/bbb" 0 "ifType != \"ethernet\" and ifMTU = 1500" "^bool:false$"
|
||||||
|
|
||||||
|
new "xpath ifType = \"ethernet\" and ifMTU = 1400"
|
||||||
|
expecteof "$PROG -f $xml2 -i /aaa/bbb" 0 "ifType = \"ethernet\" and ifMTU = 1400" "^bool:false$"
|
||||||
|
|
||||||
|
new "xpath ifType != \"ethernet\" and ifMTU = 1400"
|
||||||
|
expecteof "$PROG -f $xml2 -i /aaa/bbb" 0 "ifType != \"ethernet\" and ifMTU = 1400" "^bool:false$"
|
||||||
|
|
||||||
|
new "xpath ifType != \"atm\" or (ifMTU <= 17966 and ifMTU >= 64)"
|
||||||
|
expecteof "$PROG -f $xml2 -i /aaa/bbb" 0 "ifType != \"atm\" or (ifMTU <= 17966 and ifMTU >= 64)" "^bool:true$"
|
||||||
|
|
||||||
|
rm -rf $dir
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
# Test: XSL tests
|
|
||||||
PROG=../lib/src/clixon_util_xsl
|
|
||||||
|
|
||||||
# include err() and new() functions and creates $dir
|
|
||||||
. ./lib.sh
|
|
||||||
|
|
||||||
new "xsl test"
|
|
||||||
expecteof $PROG 0 "a
|
|
||||||
<a><b/></a>" "^0:<a><b/></a>$"
|
|
||||||
|
|
||||||
rm -rf $dir
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Test4: Yang specifics: multi-keys and empty type
|
# Yang specifics: multi-keys and empty type
|
||||||
APPNAME=example
|
APPNAME=example
|
||||||
# include err() and new() functions and creates $dir
|
# include err() and new() functions and creates $dir
|
||||||
. ./lib.sh
|
. ./lib.sh
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue