mirror of https://github.com/sipwise/klish.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
359 lines
6.5 KiB
359 lines
6.5 KiB
/*
|
|
* ------------------------------------------------------
|
|
* shell_roxml.c
|
|
*
|
|
* This file implements the means to read an XML encoded file
|
|
* and populate the CLI tree based on the contents. It implements
|
|
* the clish_xml API using roxml
|
|
* ------------------------------------------------------
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#if defined(HAVE_LIB_ROXML)
|
|
#include <errno.h>
|
|
#include <roxml.h>
|
|
#include "xmlapi.h"
|
|
|
|
/* dummy stuff ; really a node_t */
|
|
struct clish_xmldoc_s {
|
|
int dummy;
|
|
};
|
|
|
|
/* dummy stuff ; really a node_t */
|
|
struct clish_xmlnode_s {
|
|
int dummy;
|
|
};
|
|
|
|
static inline node_t *xmldoc_to_node(clish_xmldoc_t *doc)
|
|
{
|
|
return (node_t*)doc;
|
|
}
|
|
|
|
static inline node_t *xmlnode_to_node(clish_xmlnode_t *node)
|
|
{
|
|
return (node_t*)node;
|
|
}
|
|
|
|
static inline clish_xmldoc_t *node_to_xmldoc(node_t *node)
|
|
{
|
|
return (clish_xmldoc_t*)node;
|
|
}
|
|
|
|
static inline clish_xmlnode_t *node_to_xmlnode(node_t *node)
|
|
{
|
|
return (clish_xmlnode_t*)node;
|
|
}
|
|
|
|
/*
|
|
* public interface
|
|
*/
|
|
|
|
int clish_xmldoc_start(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int clish_xmldoc_stop(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
clish_xmldoc_t *clish_xmldoc_read(const char *filename)
|
|
{
|
|
node_t *doc = roxml_load_doc((char*)filename);
|
|
return node_to_xmldoc(doc);
|
|
}
|
|
|
|
void clish_xmldoc_release(clish_xmldoc_t *doc)
|
|
{
|
|
if (doc) {
|
|
node_t *node = xmldoc_to_node(doc);
|
|
roxml_release(RELEASE_ALL);
|
|
roxml_close(node);
|
|
}
|
|
}
|
|
|
|
int clish_xmldoc_is_valid(clish_xmldoc_t *doc)
|
|
{
|
|
return doc != NULL;
|
|
}
|
|
|
|
int clish_xmldoc_error_caps(clish_xmldoc_t *doc)
|
|
{
|
|
return CLISH_XMLERR_NOCAPS;
|
|
}
|
|
|
|
int clish_xmldoc_get_err_line(clish_xmldoc_t *doc)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
int clish_xmldoc_get_err_col(clish_xmldoc_t *doc)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
const char *clish_xmldoc_get_err_msg(clish_xmldoc_t *doc)
|
|
{
|
|
return "";
|
|
}
|
|
|
|
int clish_xmlnode_get_type(clish_xmlnode_t *node)
|
|
{
|
|
if (node) {
|
|
int type = roxml_get_type(xmlnode_to_node(node));
|
|
switch (type) {
|
|
case ROXML_ELM_NODE:
|
|
return CLISH_XMLNODE_ELM;
|
|
case ROXML_TXT_NODE:
|
|
return CLISH_XMLNODE_TEXT;
|
|
case ROXML_CMT_NODE:
|
|
return CLISH_XMLNODE_COMMENT;
|
|
case ROXML_PI_NODE:
|
|
return CLISH_XMLNODE_PI;
|
|
case ROXML_ATTR_NODE:
|
|
return CLISH_XMLNODE_ATTR;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return CLISH_XMLNODE_UNKNOWN;
|
|
}
|
|
|
|
clish_xmlnode_t *clish_xmldoc_get_root(clish_xmldoc_t *doc)
|
|
{
|
|
node_t *root;
|
|
char *name = NULL;
|
|
|
|
if (!doc)
|
|
return NULL;
|
|
root = roxml_get_root(xmldoc_to_node(doc));
|
|
if (!root)
|
|
return NULL;
|
|
/* The root node is always documentRoot since libroxml-2.2.2. */
|
|
/* It's good but not compatible with another XML parsers. */
|
|
name = roxml_get_name(root, NULL, 0);
|
|
if (0 == strcmp(name, "documentRoot"))
|
|
root = roxml_get_chld(root, NULL, 0);
|
|
roxml_release(name);
|
|
|
|
return node_to_xmlnode(root);
|
|
}
|
|
|
|
clish_xmlnode_t *clish_xmlnode_parent(clish_xmlnode_t *node)
|
|
{
|
|
if (node) {
|
|
node_t *roxn = xmlnode_to_node(node);
|
|
node_t *root = roxml_get_root(roxn);
|
|
if (roxn != root)
|
|
return node_to_xmlnode(roxml_get_parent(roxn));
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
clish_xmlnode_t *clish_xmlnode_next_child(clish_xmlnode_t *parent,
|
|
clish_xmlnode_t *curchild)
|
|
{
|
|
node_t *roxc;
|
|
|
|
if (!parent)
|
|
return NULL;
|
|
|
|
roxc = xmlnode_to_node(curchild);
|
|
|
|
if (roxc) {
|
|
return node_to_xmlnode(roxml_get_next_sibling(roxc));
|
|
} else {
|
|
node_t *roxp = xmlnode_to_node(parent);
|
|
node_t *child = NULL;
|
|
int count;
|
|
|
|
count = roxml_get_chld_nb(roxp);
|
|
if (count)
|
|
child = roxml_get_chld(roxp, NULL, 0);
|
|
|
|
return node_to_xmlnode(child);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int i_is_needle(char *src, const char *needle)
|
|
{
|
|
int nlen = strlen(needle);
|
|
int slen = strlen(src);
|
|
|
|
if (slen >= nlen) {
|
|
if (strncmp(src, needle, nlen) == 0)
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* warning: dst == src is valid */
|
|
static void i_decode_and_copy(char *dst, char *src)
|
|
{
|
|
while (*src) {
|
|
if (*src == '&') {
|
|
if (i_is_needle(src, "<")) {
|
|
*dst++ = '<';
|
|
src += 4;
|
|
} else if (i_is_needle(src, ">")) {
|
|
*dst++ = '>';
|
|
src += 4;
|
|
} else if (i_is_needle(src, "&")) {
|
|
*dst++ = '&';
|
|
src += 5;
|
|
} else {
|
|
*dst++ = *src++;
|
|
}
|
|
} else {
|
|
*dst++ = *src++;
|
|
}
|
|
}
|
|
*dst++ = 0;
|
|
}
|
|
|
|
char *clish_xmlnode_fetch_attr(clish_xmlnode_t *node,
|
|
const char *attrname)
|
|
{
|
|
node_t *roxn;
|
|
node_t *attr;
|
|
char *content;
|
|
|
|
if (!node || !attrname)
|
|
return NULL;
|
|
|
|
roxn = xmlnode_to_node(node);
|
|
attr = roxml_get_attr(roxn, (char*)attrname, 0);
|
|
|
|
content = roxml_get_content(attr, NULL, 0, NULL);
|
|
if (content) {
|
|
i_decode_and_copy(content, content);
|
|
}
|
|
return content;
|
|
}
|
|
|
|
static int i_get_content(node_t *n, char *v, unsigned int *vl)
|
|
{
|
|
char *c;
|
|
int len;
|
|
|
|
c = roxml_get_content(n, NULL, 0, NULL);
|
|
if (c) {
|
|
len = strlen(c) + 1;
|
|
if (len <= *vl) {
|
|
i_decode_and_copy(v, c);
|
|
roxml_release(c);
|
|
return 0;
|
|
} else {
|
|
*vl = len;
|
|
roxml_release(c);
|
|
return -E2BIG;
|
|
}
|
|
}
|
|
*vl = (unsigned int)-1;
|
|
return -ENOMEM;
|
|
}
|
|
|
|
int clish_xmlnode_get_content(clish_xmlnode_t *node, char *content,
|
|
unsigned int *contentlen)
|
|
{
|
|
if (content && contentlen && *contentlen)
|
|
*content = 0;
|
|
|
|
if (!node || !content || !contentlen)
|
|
return -EINVAL;
|
|
|
|
if (*contentlen <= 1)
|
|
return -EINVAL;
|
|
|
|
*content = 0;
|
|
|
|
return i_get_content(xmlnode_to_node(node), content, contentlen);
|
|
}
|
|
|
|
static int i_get_name(node_t *n, char *v, unsigned int *vl)
|
|
{
|
|
char *c;
|
|
int len;
|
|
|
|
c = roxml_get_name(n, NULL, 0);
|
|
if (c) {
|
|
len = strlen(c) + 1;
|
|
if (len <= *vl) {
|
|
snprintf(v, *vl, "%s", c);
|
|
v[*vl - 1] = '\0';
|
|
roxml_release(c);
|
|
return 0;
|
|
} else {
|
|
*vl = len;
|
|
roxml_release(c);
|
|
return -E2BIG;
|
|
}
|
|
}
|
|
*vl = (unsigned int)-1;
|
|
return -ENOMEM;
|
|
}
|
|
|
|
int clish_xmlnode_get_name(clish_xmlnode_t *node, char *name,
|
|
unsigned int *namelen)
|
|
{
|
|
if (name && namelen && *namelen)
|
|
*name = 0;
|
|
|
|
if (!node || !name || !namelen)
|
|
return -EINVAL;
|
|
|
|
if (*namelen <= 1)
|
|
return -EINVAL;
|
|
|
|
*name = 0;
|
|
|
|
return i_get_name(xmlnode_to_node(node), name, namelen);
|
|
}
|
|
|
|
void clish_xmlnode_print(clish_xmlnode_t *node, FILE *out)
|
|
{
|
|
node_t *roxn;
|
|
char *name;
|
|
|
|
roxn = xmlnode_to_node(node);
|
|
name = roxml_get_name(roxn, NULL, 0);
|
|
if (name) {
|
|
fprintf(out, "<%s", name);
|
|
roxml_release(name);
|
|
if (roxml_get_attr_nb(roxn)) {
|
|
int attr_count = roxml_get_attr_nb(roxn);
|
|
int attr_pos;
|
|
for (attr_pos = 0; attr_pos < attr_count; ++attr_pos) {
|
|
node_t *attr = roxml_get_attr(roxn, NULL, attr_pos);
|
|
char *n = roxml_get_name(attr, NULL, 0);
|
|
char *v = roxml_get_content(attr, NULL, 0, NULL);
|
|
if (n && v) {
|
|
fprintf(out, " %s='%s'", n, v);
|
|
}
|
|
if (v)
|
|
roxml_release(v);
|
|
if (n)
|
|
roxml_release(n);
|
|
}
|
|
}
|
|
fprintf(out, ">");
|
|
}
|
|
}
|
|
|
|
void clish_xml_release(void *p)
|
|
{
|
|
if (p) {
|
|
roxml_release(p);
|
|
}
|
|
}
|
|
|
|
#endif /* HAVE_LIB_ROXML */
|
|
|