ossp-pkg/cfg/cfg_node.c
1.9
/*
** OSSP cfg - Configuration Parsing
** Copyright (c) 1999-2002 Ralf S. Engelschall <rse@engelschall.com>
** Copyright (c) 1999-2002 The OSSP Project (http://www.ossp.org/)
** Copyright (c) 2001-2002 Cable & Wireless Deutschland (http://www.cw.com/de/)
**
** This file is part of OSSP cfg, a configuration parsing
** library which can be found at http://www.ossp.org/pkg/lib/cfg/.
**
** Permission to use, copy, modify, and distribute this software for
** any purpose with or without fee is hereby granted, provided that
** the above copyright notice and this permission notice appear in all
** copies.
**
** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRCFG, STRICT LIABILITY,
** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
**
** cfg_node.c: configuration nodes
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include "cfg_main.h"
#include "cfg_node.h"
cfg_rc_t cfg_node_create(cfg_t *cfg, cfg_node_t **node)
{
cfg_node_t *n;
if (node == NULL)
return CFG_ERR_ARG;
if ((n = malloc(sizeof(cfg_node_t))) == NULL)
return CFG_ERR_SYS;
n->parent = NULL;
n->lbroth = NULL;
n->rbroth = NULL;
n->child1 = NULL;
n->srcname = NULL;
n->srcpos = 0;
n->type = CFG_NODE_TYPE_ARG;
n->token = NULL;
cfg_data_init(&n->data);
*node = n;
return CFG_OK;
}
cfg_rc_t cfg_node_destroy(cfg_t *cfg, cfg_node_t *node)
{
if (node == NULL)
return CFG_ERR_ARG;
if (node->token != NULL)
free(node->token);
if (node->srcname != NULL)
free(node->srcname);
free(node);
return CFG_OK;
}
cfg_rc_t cfg_node_clone(cfg_t *cfg, cfg_node_t *node, cfg_node_t **node2)
{
cfg_node_t *n;
if (node == NULL || node2 == NULL)
return CFG_ERR_ARG;
if ((n = malloc(sizeof(cfg_node_t))) == NULL)
return CFG_ERR_SYS;
n->parent = node->parent;
n->lbroth = node->lbroth;
n->rbroth = node->rbroth;
n->child1 = node->child1;
n->srcname = (node->srcname != NULL ? strdup(node->srcname) : NULL);
n->srcpos = node->srcpos;
n->type = node->type;
n->token = (node->token != NULL ? strdup(node->token) : NULL);
cfg_data_copy(&node->data, &n->data);
*node2 = n;
return CFG_OK;
}
cfg_rc_t cfg_node_set(cfg_t *cfg, cfg_node_t *node, cfg_node_attr_t attr, ...)
{
va_list ap;
if (node == NULL)
return CFG_ERR_ARG;
va_start(ap, attr);
switch (attr) {
case CFG_NODE_ATTR_PARENT: {
node->parent = (cfg_node_t *)va_arg(ap, cfg_node_t *);
break;
}
case CFG_NODE_ATTR_LBROTH: {
return CFG_ERR_USE;
}
case CFG_NODE_ATTR_RBROTH: {
node->rbroth = (cfg_node_t *)va_arg(ap, cfg_node_t *);
break;
}
case CFG_NODE_ATTR_CHILD1: {
node->child1 = (cfg_node_t *)va_arg(ap, cfg_node_t *);
break;
}
case CFG_NODE_ATTR_CHILDL: {
return CFG_ERR_USE;
}
case CFG_NODE_ATTR_CHILDS: {
return CFG_ERR_USE;
}
case CFG_NODE_ATTR_NODES: {
return CFG_ERR_USE;
}
case CFG_NODE_ATTR_DEPTH: {
return CFG_ERR_USE;
}
case CFG_NODE_ATTR_SRCNAME: {
if (node->srcname != NULL)
free(node->srcname);
node->srcname = (char *)va_arg(ap, char *);
if (node->srcname != NULL)
node->srcname = strdup(node->srcname);
break;
}
case CFG_NODE_ATTR_SRCPOS: {
node->srcpos = (int)va_arg(ap, int);
break;
}
case CFG_NODE_ATTR_TYPE: {
node->type = (cfg_node_type_t)va_arg(ap, cfg_node_type_t);
break;
}
case CFG_NODE_ATTR_TOKEN: {
if (node->token != NULL)
free(node->token);
node->token = (char *)va_arg(ap, char *);
if (node->token != NULL)
node->token = strdup(node->token);
break;
}
case CFG_NODE_ATTR_DATA: {
return CFG_ERR_USE;
}
default:
return CFG_ERR_ARG;
}
va_end(ap);
return CFG_OK;
}
static int cfg_node_get_nodes(cfg_node_t *node)
{
int n;
n = 0;
if (node != NULL) {
n++;
if ((node = node->child1) != NULL) {
n += cfg_node_get_nodes(node);
if ((node = node->rbroth) != NULL)
n += cfg_node_get_nodes(node);
}
}
return n;
}
cfg_rc_t cfg_node_get(cfg_t *cfg, cfg_node_t *node, cfg_node_attr_t attr, ...)
{
va_list ap;
if (node == NULL)
return CFG_ERR_ARG;
va_start(ap, attr);
switch (attr) {
case CFG_NODE_ATTR_PARENT: {
cfg_node_t **n = (cfg_node_t **)va_arg(ap, void *);
if (n == NULL)
return CFG_ERR_ARG;
*n = node->parent;
break;
}
case CFG_NODE_ATTR_LBROTH: {
cfg_node_t **np = (cfg_node_t **)va_arg(ap, void *);
cfg_node_t *n;
if (np == NULL)
return CFG_ERR_ARG;
*np = NULL;
if ((n = node->parent) != NULL) {
if ((n = n->child1) != NULL) {
while (n->rbroth != node && n->rbroth != NULL)
n = n->rbroth;
if (n->rbroth == node)
*np = n;
}
}
break;
}
case CFG_NODE_ATTR_RBROTH: {
cfg_node_t **n = (cfg_node_t **)va_arg(ap, void *);
if (n == NULL)
return CFG_ERR_ARG;
*n = node->rbroth;
break;
}
case CFG_NODE_ATTR_CHILD1: {
cfg_node_t **n = (cfg_node_t **)va_arg(ap, void *);
if (n == NULL)
return CFG_ERR_ARG;
*n = node->child1;
break;
}
case CFG_NODE_ATTR_CHILDL: {
cfg_node_t **n = (cfg_node_t **)va_arg(ap, void *);
if (n == NULL)
return CFG_ERR_ARG;
if ((*n = node->child1) != NULL)
while ((*n)->rbroth != NULL)
*n = (*n)->rbroth;
break;
}
case CFG_NODE_ATTR_CHILDS: {
int *c = (int *)va_arg(ap, int *);
cfg_node_t *n;
if (c == NULL)
return CFG_ERR_ARG;
*c = 0;
if ((n = node->child1) != NULL) {
(*c)++;
while (n->rbroth != NULL) {
n = n->rbroth;
(*c)++;
}
}
break;
}
case CFG_NODE_ATTR_NODES: {
int *k = (int *)va_arg(ap, int *);
if (k == NULL)
return CFG_ERR_ARG;
*k = cfg_node_get_nodes(node);
break;
}
case CFG_NODE_ATTR_DEPTH: {
int *k = (int *)va_arg(ap, int *);
cfg_node_t *n;
if (k == NULL)
return CFG_ERR_ARG;
*k = 0;
n = node;
while ((n = n->parent) != NULL)
(*k)++;
break;
}
case CFG_NODE_ATTR_SRCNAME: {
char **name = (char **)va_arg(ap, char **);
if (name == NULL)
return CFG_ERR_ARG;
*name = node->srcname;
break;
}
case CFG_NODE_ATTR_SRCPOS: {
int *pos = (int *)va_arg(ap, int *);
if (pos == NULL)
return CFG_ERR_ARG;
*pos = node->srcpos;
break;
}
case CFG_NODE_ATTR_TYPE: {
cfg_node_type_t *type = (cfg_node_type_t *)va_arg(ap, void *);
if (type == NULL)
return CFG_ERR_ARG;
*type = node->type;
break;
}
case CFG_NODE_ATTR_TOKEN: {
char **token = (char **)va_arg(ap, char **);
if (token == NULL)
return CFG_ERR_ARG;
*token = node->token;
break;
}
case CFG_NODE_ATTR_DATA: {
cfg_data_t **data = (cfg_data_t **)va_arg(ap, void *);
if (data == NULL)
return CFG_ERR_ARG;
*data = &(node->data);
break;
}
default:
return CFG_ERR_ARG;
}
va_end(ap);
return CFG_OK;
}
cfg_rc_t cfg_node_root(cfg_t *cfg, cfg_node_t **node)
{
if (cfg == NULL || node == NULL)
return CFG_ERR_ARG;
*node = cfg->root;
return CFG_OK;
}
cfg_rc_t cfg_node_select(cfg_t *cfg, cfg_node_t *node, cfg_node_t **node2, const char *fmt, ...)
{
#if 0
cfg_node_t *n;
va_list ap;
char *cpB;
char *cpE;
char *spec;
if (cfg == NULL || node == NULL || node2 == NULL || spec == NULL)
return CFG_ERR_ARG;
/* on-the-fly create or just take over specification string */
va_start(ap, fmt);
spec = l2_util_vasprintf(fmt, ap);
va_end(ap);
/* enter the parsing loop */
cpE = spec;
while (*cpE != '\0') {
/* determine begin of parameter name */
cpB = cpE;
if ((n = strspn(cpB, " \t\r\n")) > 0)
cpB += n;
/* determine end of parameter name */
cpE = cpB;
if ((n = strspn(cpB, " \t\r\n")) > 0)
cpB += n;
}
#endif
return CFG_OK;
}
cfg_rc_t
cfg_node_find(
cfg_t *cfg,
cfg_node_t *node,
cfg_rc_t (*cb_fct_cmp)(cfg_t *, cfg_node_t *, void *),
void *cb_ctx_cmp,
cfg_node_t **cont)
{
#if 0
cfg_rc_t rc;
if (cfg == NULL)
return CFG_ERR_ARG;
if (node != NULL) {
cb_fct(cb_ctx, node);
if (node->child1 != NULL)
if ((rc = cfg_node_apply(node->child1, cb_fct, cb_ctx)) != CFG_OK)
return rc;
if (node->rbroth != NULL)
if ((rc = cfg_node_apply(node->rbroth, cb_fct, cb_ctx)) != CFG_OK)
return rc;
}
#endif
return CFG_OK;
}
cfg_rc_t
cfg_node_apply(
cfg_t *cfg,
cfg_node_t *node,
cfg_rc_t (*cb_fct_cmp)(cfg_t *, cfg_node_t *, void *),
void *cb_ctx_cmp,
cfg_rc_t (*cb_fct_cb)(cfg_t *, cfg_node_t *, void *),
void *cb_ctx_cb)
{
cfg_rc_t rc;
if (cfg == NULL || node == NULL || cb_fct_cb == NULL)
return CFG_ERR_ARG;
node = NULL;
if (node == NULL)
if ((node = cfg->root) == NULL)
return CFG_OK;
do {
if ((rc = cb_fct_cb(cfg, node, cb_ctx_cb)) != CFG_OK)
return rc;
} while ((rc = cfg_node_find(cfg, node, cb_fct_cmp, cb_ctx_cmp, &node)) == CFG_OK);
if (rc != CFG_OK && rc != CFG_ERR_NDE)
return rc;
return CFG_OK;
}
cfg_rc_t
cfg_node_cmp(
cfg_t *cfg,
cfg_node_t *node,
void *token)
{
if (cfg == NULL || node == NULL || token == NULL)
return CFG_ERR_NDE;
if (node->token == NULL && token == NULL)
return CFG_OK;
if (node->token == NULL || token == NULL)
return CFG_ERR_NDE;
if (strcmp(node->token, (char *)token) == 0)
return CFG_OK;
return CFG_ERR_NDE;
}
cfg_rc_t cfg_node_link(cfg_t *cfg, cfg_node_t *node, cfg_node_attr_t attr, cfg_node_t *node2)
{
cfg_node_t *n;
if (node == NULL || node2 == NULL)
return CFG_ERR_ARG;
if (attr == CFG_NODE_ATTR_RBROTH) {
/* make node a rbroth */
n = node2;
n->parent = node->parent;
while (n->rbroth != NULL) {
n->parent = node->parent;
n = n->rbroth;
}
n->rbroth = node->rbroth;
node->rbroth = node2;
}
else if (attr == CFG_NODE_ATTR_CHILD1) {
/* make node a child1 */
n = node2;
n->parent = node;
while (n->rbroth != NULL) {
n->parent = node;
n = n->rbroth;
}
n->rbroth = node->child1;
node->child1 = node2;
}
/* FIXME more linkage possibilities */
else
return CFG_ERR_ARG;
return CFG_OK;
}
cfg_rc_t cfg_node_unlink(cfg_t *cfg, cfg_node_t *node)
{
cfg_node_t *n;
if (node == NULL)
return CFG_ERR_ARG;
if (node->parent == NULL)
return CFG_OK;
if (node->parent->child1 == node) {
/* node was a child1 */
node->parent->child1 = node->rbroth;
}
else {
/* node was a rbroth */
n = node->parent->child1;
while (n->rbroth != node)
n = n->rbroth;
n->rbroth = node->rbroth;
}
return CFG_OK;
}