*** /dev/null Tue Mar 11 06:03:04 2025
--- - Tue Mar 11 06:03:19 2025
***************
*** 0 ****
--- 1,834 ----
+ /*
+ ** OSSP cfg - Configuration Parsing
+ ** Copyright (c) 2002-2004 Ralf S. Engelschall <rse@engelschall.com>
+ ** Copyright (c) 2002-2004 The OSSP Project (http://www.ossp.org/)
+ ** Copyright (c) 2002-2004 Cable & Wireless (http://www.cw.com/)
+ **
+ ** 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 CONTRACT, 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 <limits.h>
+
+ #include "cfg_global.h"
+ #include "cfg_main.h"
+ #include "cfg_node.h"
+ #include "cfg_fmt.h"
+
+ /* create a configuration node */
+ cfg_rc_t
+ cfg_node_create(
+ cfg_t *cfg,
+ cfg_node_t **node)
+ {
+ cfg_node_t *n;
+ cfg_rc_t rc;
+
+ /* argument sanity checking */
+ if (node == NULL)
+ return CFG_ERR_ARG;
+
+ /* allocate memory */
+ if ((rc = cfg_grid_alloc(cfg->grid_nodes, (void **)(void *)&n)) != CFG_OK)
+ return rc;
+
+ /* initialize node attributes */
+ n->parent = NULL;
+ n->rbroth = NULL;
+ n->child1 = NULL;
+ n->type = CFG_NODE_TYPE_ARG;
+ n->token = NULL;
+ cfg_data_init(&n->data);
+ n->srcname = NULL;
+ n->srcpos = 0;
+ *node = n;
+
+ return CFG_OK;
+ }
+
+ /* destroy a configuration node */
+ cfg_rc_t
+ cfg_node_destroy(
+ cfg_t *cfg,
+ cfg_node_t *node)
+ {
+ /* argument sanity checking */
+ if (node == NULL)
+ return CFG_ERR_ARG;
+
+ /* destroy memory */
+ if (node->token != NULL)
+ free(node->token);
+ if (node->srcname != NULL)
+ free(node->srcname);
+ cfg_grid_free(cfg->grid_nodes, node);
+
+ return CFG_OK;
+ }
+
+ /* clone a node */
+ cfg_rc_t
+ cfg_node_clone(
+ cfg_t *cfg,
+ cfg_node_t *node,
+ cfg_node_t **node2)
+ {
+ cfg_node_t *n;
+ cfg_rc_t rc;
+
+ /* argument sanity checking */
+ if (node == NULL || node2 == NULL)
+ return CFG_ERR_ARG;
+
+ /* allocate memory for new node */
+ if ((rc = cfg_grid_alloc(cfg->grid_nodes, (void **)(void *)&n)) != CFG_OK)
+ return rc;
+
+ /* clone node attributes */
+ n->parent = node->parent;
+ n->rbroth = node->rbroth;
+ n->child1 = node->child1;
+ n->type = node->type;
+ n->token = (node->token != NULL ? strdup(node->token) : NULL);
+ cfg_data_copy(&node->data, &n->data);
+ n->srcname = (node->srcname != NULL ? strdup(node->srcname) : NULL);
+ n->srcpos = node->srcpos;
+ *node2 = n;
+
+ return CFG_OK;
+ }
+
+ /* set a node attribute */
+ cfg_rc_t
+ cfg_node_set(
+ cfg_t *cfg,
+ cfg_node_t *node,
+ cfg_node_attr_t attr,
+ ...)
+ {
+ va_list ap;
+
+ /* argument sanity checking */
+ if (node == NULL)
+ return CFG_ERR_ARG;
+
+ /* dispatch into individual attribute handling */
+ 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; /* cannot be set, only get */
+ }
+ 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; /* cannot be set, only get */
+ }
+ case CFG_NODE_ATTR_CHILDS: {
+ return CFG_ERR_USE; /* cannot be set, only get */
+ }
+ case CFG_NODE_ATTR_NODES: {
+ return CFG_ERR_USE; /* cannot be set, only get */
+ }
+ case CFG_NODE_ATTR_DEPTH: {
+ return CFG_ERR_USE; /* cannot be set, only get */
+ }
+ 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;
+ }
+ 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;
+ }
+ default:
+ return CFG_ERR_ARG;
+ }
+ va_end(ap);
+
+ return CFG_OK;
+ }
+
+ /* INTERNAL: calculate number of nodes */
+ 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;
+
+ /* argument sanity checking */
+ if (node == NULL)
+ return CFG_ERR_ARG;
+
+ /* dispatch into individual attribute handling */
+ 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_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;
+ }
+ 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;
+ }
+ default:
+ return CFG_ERR_ARG;
+ }
+ va_end(ap);
+
+ return CFG_OK;
+ }
+
+ /* get and/or set root node */
+ cfg_rc_t
+ cfg_node_root(
+ cfg_t *cfg,
+ cfg_node_t *node,
+ cfg_node_t **node_old)
+ {
+ /* argument sanity checking */
+ if (cfg == NULL || (node == NULL && node_old == NULL))
+ return CFG_ERR_ARG;
+
+ /* optionally get old root node pointer */
+ if (node_old != NULL)
+ *node_old = cfg->root;
+
+ /* optionally set new root node pointer */
+ if (node != NULL)
+ cfg->root = node;
+
+ return CFG_OK;
+ }
+
+ /* forward declarations for internal stepping functions */
+ static cfg_rc_t
+ cfg_node_select_step1(
+ cfg_t *, cfg_node_t *, cfg_node_t ***, long *, const char *);
+ static cfg_rc_t
+ cfg_node_select_step2(
+ cfg_t *, cfg_node_t *, cfg_node_t ***, long *, const char *, const char *, size_t, long, long, long *);
+
+ /* INTERNAL: selection stepping function (part 3, matching node processing) */
+ static cfg_rc_t
+ cfg_node_select_step3(
+ cfg_t *cfg,
+ cfg_node_t *node,
+ cfg_node_t ***result_vec, long *result_len,
+ const char *spec,
+ const char *cpSel, size_t nSel,
+ long nFilMin, long nFilMax,
+ long *nFound)
+ {
+ cfg_rc_t rc;
+
+ fprintf(stderr, " step3: (1) cpSel=\"%s\", nSel=%d, spec=\"%s\", nFilMin=%ld, nFilMax=%ld, nFound=%ld\n",
+ cpSel, nSel, spec, nFilMin, nFilMax, *nFound);
+
+ if (spec[0] == '\0') {
+ /* end of selection, node found */
+ (*nFound)++;
+ fprintf(stderr, " step3: (2) found node!!\n");
+ fprintf(stderr, " step3: current node=0x%lx type=%s token=\"%s\"\n",
+ (unsigned long)node,
+ (node != NULL ? (node->type == CFG_NODE_TYPE_SEQ ? "SEQ" : (node->type == CFG_NODE_TYPE_DIR ? "DIR" : "ARG")) : "<NULL>/.."),
+ (node != NULL ? (node->token != NULL ? node->token : "<NULL>") : "<NULL>/.."));
+ if (nFilMin <= *nFound && *nFound <= nFilMax) {
+ if (result_len != NULL) {
+ (*result_len)++;
+ if (result_vec != NULL) {
+ if ((*result_vec = (cfg_node_t **)realloc(*result_vec, sizeof(cfg_node_t *)*((*result_len)+1))) == NULL)
+ return CFG_ERR_SYS;
+ (*result_vec)[(*result_len)-1] = node;
+ (*result_vec)[(*result_len)] = NULL;
+ }
+ }
+ }
+ rc = CFG_OK;
+ }
+ else {
+ /* start over with next step */
+ rc = cfg_node_select_step1(cfg, node, result_vec, result_len, spec);
+ }
+ return rc;
+ }
+
+ /* INTERNAL: selection stepping function (part 2, node matching) */
+ static cfg_rc_t
+ cfg_node_select_step2(
+ cfg_t *cfg,
+ cfg_node_t *node,
+ cfg_node_t ***result_vec, long *result_len,
+ const char *spec,
+ const char *cpSel, size_t nSel,
+ long nFilMin, long nFilMax,
+ long *nFound)
+ {
+ cfg_rc_t rc;
+ char *token;
+ cfg_node_t *node2;
+ cfg_node_type_t type;
+
+ fprintf(stderr, " step2: (1) cpSel=\"%.*s\", nSel=%d, spec=\"%s\", nFilMin=%ld, nFilMax=%ld, nFound=%ld\n",
+ nSel, cpSel, nSel, spec, nFilMin, nFilMax, *nFound);
+ fprintf(stderr, " step2: current node=0x%lx type=%s token=\"%s\"\n",
+ (unsigned long)node,
+ (node != NULL ? (node->type == CFG_NODE_TYPE_SEQ ? "SEQ" : (node->type == CFG_NODE_TYPE_DIR ? "DIR" : "ARG")) : "<NULL>/.."),
+ (node != NULL ? (node->token != NULL ? node->token : "<NULL>") : "<NULL>/.."));
+
+ rc = CFG_OK;
+ if (nSel == 1 && strncmp(cpSel, ".", nSel) == 0) {
+ /* current node (no-op) */
+ fprintf(stderr, " step2: search current node, starting at node 0x%lx\n", (unsigned long)node);
+ rc = cfg_node_select_step3(cfg, node, result_vec, result_len, spec, cpSel, nSel, nFilMin, nFilMax, nFound);
+ }
+ else if (nSel == 2 && strncmp(cpSel, "..", nSel) == 0) {
+ /* parent node */
+ fprintf(stderr, " step2: search parent node, starting at node 0x%lx\n", (unsigned long)node);
+ if (cfg_node_get(cfg, node, CFG_NODE_ATTR_PARENT, &node) == CFG_OK && node != NULL)
+ rc = cfg_node_select_step3(cfg, node, result_vec, result_len, spec, cpSel, nSel, nFilMin, nFilMax, nFound);
+ }
+ else if (nSel == 4 && strncmp(cpSel, "....", nSel) == 0) {
+ /* anchestor nodes */
+ fprintf(stderr, " step2: search ancestor nodes, starting at node 0x%lx\n", (unsigned long)node);
+ while (cfg_node_get(cfg, node, CFG_NODE_ATTR_PARENT, &node) == CFG_OK && node != NULL)
+ if ((rc = cfg_node_select_step3(cfg, node, result_vec, result_len, spec, cpSel, nSel, nFilMin, nFilMax, nFound)) != CFG_OK)
+ break;
+ }
+ else if (nSel == 1 && strncmp(cpSel, "-", nSel) == 0) {
+ /* previous sibling node */
+ fprintf(stderr, " step2: search previous sibling node, starting at node 0x%lx\n", (unsigned long)node);
+ if ((rc = cfg_node_get(cfg, node, CFG_NODE_ATTR_LBROTH, &node)) == CFG_OK && node != NULL)
+ rc = cfg_node_select_step3(cfg, node, result_vec, result_len, spec, cpSel, nSel, nFilMin, nFilMax, nFound);
+ }
+ else if (nSel == 2 && strncmp(cpSel, "--", nSel) == 0) {
+ /* preceeding sibling nodes */
+ fprintf(stderr, " step2: search preceeding sibling nodes, starting at node 0x%lx\n", (unsigned long)node);
+ while (cfg_node_get(cfg, node, CFG_NODE_ATTR_LBROTH, &node) == CFG_OK && node != NULL)
+ if ((rc = cfg_node_select_step3(cfg, node, result_vec, result_len, spec, cpSel, nSel, nFilMin, nFilMax, nFound)) != CFG_OK)
+ break;
+ }
+ else if (nSel == 1 && strncmp(cpSel, "+", nSel) == 0) {
+ /* next sibling node */
+ fprintf(stderr, " step2: search next sibling node, starting at node 0x%lx\n", (unsigned long)node);
+ if ((rc = cfg_node_get(cfg, node, CFG_NODE_ATTR_RBROTH, &node)) == CFG_OK && node != NULL)
+ rc = cfg_node_select_step3(cfg, node, result_vec, result_len, spec, cpSel, nSel, nFilMin, nFilMax, nFound);
+ }
+ else if (nSel == 2 && strncmp(cpSel, "++", nSel) == 0) {
+ /* following sibling nodes */
+ fprintf(stderr, " step2: search following sibling nodes, starting at node 0x%lx\n", (unsigned long)node);
+ while (cfg_node_get(cfg, node, CFG_NODE_ATTR_RBROTH, &node) == CFG_OK && node != NULL)
+ if ((rc = cfg_node_select_step3(cfg, node, result_vec, result_len, spec, cpSel, nSel, nFilMin, nFilMax, nFound)) != CFG_OK)
+ break;
+ }
+ else if (nSel == 0 /* "//" */) {
+ /* descendant nodes */
+ fprintf(stderr, " step2: search descendant nodes, starting at node 0x%lx\n", (unsigned long)node);
+ #if 0 /* FIXME */
+ if ((rc = cfg_node_apply(cfg, node, NULL, NULL, cfg_node_select_step2_descendant, &descendant_ctx)
+ cfg_rc_t cfg_node_select_step2_descendant(cfg_t *cfg, cfg_node_t *node, void *_ctx));
+ #endif
+ if ((rc = cfg_node_get(cfg, node, CFG_NODE_ATTR_CHILD1, &node)) == CFG_OK && node != NULL) {
+ do {
+ if ((rc = cfg_node_select_step3(cfg, node, result_vec, result_len, spec, cpSel, nSel, nFilMin, nFilMax, nFound)) != CFG_OK)
+ return rc;
+ if ((rc = cfg_node_select_step2(cfg, node, result_vec, result_len, spec, cpSel, nSel, nFilMin, nFilMax, nFound)) != CFG_OK)
+ return rc;
+ } while ((rc = cfg_node_get(cfg, node, CFG_NODE_ATTR_RBROTH, &node)) == CFG_OK && node != NULL);
+ }
+ return CFG_OK;
+ }
+ else {
+ /* child node */
+ fprintf(stderr, " step2: search child nodes, starting at node 0x%lx\n", (unsigned long)node);
+ if ((rc = cfg_node_get(cfg, node, CFG_NODE_ATTR_CHILD1, &node)) == CFG_OK && node != NULL) {
+ do {
+ if ((rc = cfg_node_get(cfg, node, CFG_NODE_ATTR_TOKEN, &token)) != CFG_OK)
+ continue;
+ if ((rc = cfg_node_get(cfg, node, CFG_NODE_ATTR_TYPE, &type)) == CFG_OK && type == CFG_NODE_TYPE_DIR) {
+ if ((rc = cfg_node_get(cfg, node, CFG_NODE_ATTR_CHILD1, &node2)) != CFG_OK || node2 == NULL)
+ continue;
+ if ((rc = cfg_node_get(cfg, node2, CFG_NODE_ATTR_TOKEN, &token)) != CFG_OK)
+ continue;
+ }
+ if (token != NULL) {
+ size_t l = strlen(token);
+ fprintf(stderr, " step2: compare child node: token \"%s\"\n", token);
+ if ( (l == 1 && nSel == 1 && token[0] == '*')
+ || (l == nSel && strncmp(token, cpSel, nSel) == 0)) {
+ if ((rc = cfg_node_select_step3(cfg, node, result_vec, result_len, spec, cpSel, nSel, nFilMin, nFilMax, nFound)) != CFG_OK)
+ return rc;
+ }
+ }
+ } while ((rc = cfg_node_get(cfg, node, CFG_NODE_ATTR_RBROTH, &node)) == CFG_OK && node != NULL);
+ }
+ return CFG_OK;
+ }
+ return rc;
+ }
+
+ /* INTERNAL: selection stepping function (part 1, selection parsing) */
+ static cfg_rc_t
+ cfg_node_select_step1(
+ cfg_t *cfg,
+ cfg_node_t *node,
+ cfg_node_t ***result_vec, long *result_len,
+ const char *spec)
+ {
+ const char *cpSel; size_t nSel;
+ long nFilMin, nFilMax;
+ long n;
+ const char *cp;
+ char *cp2;
+ cfg_rc_t rc;
+ long nFound;
+
+ fprintf(stderr, " step1: (0) spec=\"%s\"\n", spec);
+
+ /* stop processing if spec is empty */
+ if (spec[0] == '\0')
+ return CFG_OK;
+
+ /* determine selection step information */
+ cpSel = spec;
+ nSel = strcspn(cpSel, "[/");
+ cp = cpSel+nSel;
+ nFilMin = 1;
+ nFilMax = LONG_MAX;
+ if (*cp == '[') {
+ cp++;
+ n = strtol(cp, &cp2, 10);
+ if (cp2 > cp && n != 0)
+ nFilMin = n;
+ cp = cp2;
+ if (*cp == ',') {
+ cp++;
+ n = strtol(cp, &cp2, 10);
+ if (cp2 > cp && n != 0)
+ nFilMax = n;
+ cp = cp2;
+ }
+ else
+ nFilMax = nFilMin;
+ if (*cp != ']') {
+ cfg_error_info(cfg, CFG_ERR_ARG, "invalid selection specification filter range");
+ return CFG_ERR_ARG;
+ }
+ cp++;
+ }
+ if (*cp == '/')
+ cp++;
+ spec = cp;
+
+ fprintf(stderr, " step1: (1) cpSel=\"%s\", nSel=%d, spec=\"%s\", nFilMin=%ld, nFilMax=%ld\n",
+ cpSel, nSel, spec, nFilMin, nFilMax);
+
+ /* perform pre-selection if filter range is relative to last element */
+ if (nFilMin < 0 || nFilMax < 0) {
+ nFound = 0;
+ fprintf(stderr, " step1: pre-selection start\n");
+ if ((rc = cfg_node_select_step2(cfg, node, NULL, NULL, spec, cpSel, nSel, 1, LONG_MAX, &nFound)) != CFG_OK)
+ return rc;
+ fprintf(stderr, " step1: (1b) cpSel=\"%s\", nSel=%d, spec=\"%s\", nFilMin=%ld, nFilMax=%ld nFound=%ld\n",
+ cpSel, nSel, spec, nFilMin, nFilMax, nFound);
+ fprintf(stderr, " step1: pre-selection end\n");
+ if (nFound == 0)
+ return CFG_OK;
+ if (nFilMin < 0) {
+ nFilMin = nFound + (nFilMin+1);
+ if (nFilMin < 1)
+ nFilMin = 1;
+ }
+ if (nFilMax < 0) {
+ nFilMax = nFound + (nFilMax+1);
+ if (nFilMax < 1)
+ nFilMax = 1;
+ }
+ }
+
+ fprintf(stderr, " step1: (2) cpSel=\"%s\", nSel=%d, spec=\"%s\", nFilMin=%ld, nFilMax=%ld\n",
+ cpSel, nSel, spec, nFilMin, nFilMax);
+
+ /* perform real selection */
+ nFound = 0;
+ if ((rc = cfg_node_select_step2(cfg, node, result_vec, result_len, spec, cpSel, nSel, nFilMin, nFilMax, &nFound)) != CFG_OK)
+ return rc;
+
+ fprintf(stderr, " step1: (3) cpSel=\"%s\", nSel=%d, spec=\"%s\", nFilMin=%ld, nFilMax=%ld nFound=%ld\n",
+ cpSel, nSel, spec, nFilMin, nFilMax, nFound);
+
+ return CFG_OK;
+ }
+
+ /* select a node */
+ cfg_rc_t
+ cfg_node_select(
+ cfg_t *cfg,
+ cfg_node_t *node,
+ cfg_node_t ***result_vec,
+ const char *fmt,
+ ...)
+ {
+ cfg_rc_t rc;
+ va_list ap;
+ char *spec;
+ char *cp;
+ long result_len;
+
+ /* argument sanity checking */
+ if (cfg == NULL || result_vec == NULL || fmt == NULL)
+ return CFG_ERR_ARG;
+
+ /* on-the-fly create or just take over specification string */
+ va_start(ap, fmt);
+ spec = cfg_fmt_vasprintf(fmt, ap);
+ va_end(ap);
+ if (spec == NULL)
+ return CFG_ERR_FMT;
+ fprintf(stderr, "select: (1) spec=\"%s\"\n", spec);
+
+ /* special cases for absolute (start from root-node) selection */
+ cp = spec;
+ if (cp[0] == '/') {
+ /* <any,"/x"> is same as <root,"x"> */
+ if (node != NULL)
+ return CFG_ERR_USE;
+ node = cfg->root;
+ cp++;
+ }
+ else if (node == NULL) {
+ /* <NULL, "..."> is same as <root, "..."> */
+ node = cfg->root;
+ }
+ fprintf(stderr, "select: (2) spec=\"%s\"\n", cp);
+
+ /* initialize result node array */
+ result_len = 0;
+ if ((*result_vec = (cfg_node_t **)malloc(sizeof(cfg_node_t *)*(result_len+1))) == NULL)
+ return CFG_ERR_SYS;
+ (*result_vec)[result_len] = NULL;
+
+ /* perform the selection stepping */
+ if ((rc = cfg_node_select_step1(cfg, node, result_vec, &result_len, cp)) != CFG_OK) {
+ free(*result_vec);
+ return rc;
+ }
+ fprintf(stderr, "select: (3) result_len=%ld\n", result_len);
+
+ return CFG_OK;
+ }
+
+ /* return next matching node (iteration) */
+ 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)
+ {
+ /* FIXME */
+ return CFG_ERR_INT;
+ }
+
+ /* apply for each matching node (recursion) */
+ 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;
+
+ /* argument sanity checking */
+ if (cfg == NULL)
+ return CFG_ERR_ARG;
+ if (node != NULL) {
+ if ((rc = cb_fct_cmp(cfg, node, cb_ctx_cmp)) == CFG_OK)
+ cb_fct_cb(cfg, node, cb_ctx_cb);
+ if (rc != CFG_ERR_NDE)
+ return rc;
+ if (node->child1 != NULL)
+ if ((rc = cfg_node_apply(cfg, node->child1,
+ cb_fct_cmp, cb_ctx_cmp,
+ cb_fct_cb, cb_ctx_cb)) != CFG_OK)
+ return rc;
+ if (node->rbroth != NULL)
+ if ((rc = cfg_node_apply(cfg, node->rbroth,
+ cb_fct_cmp, cb_ctx_cmp,
+ cb_fct_cb, cb_ctx_cb)) != CFG_OK)
+ return rc;
+ }
+ return CFG_OK;
+ }
+
+ /* compare two nodes */
+ cfg_rc_t
+ cfg_node_cmp(
+ cfg_t *cfg,
+ cfg_node_t *node,
+ void *token)
+ {
+ /* argument sanity checking */
+ 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;
+ }
+
+ /* link to nodes together */
+ 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;
+
+ /* argument sanity checking */
+ 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;
+ }
+
+ /* unlink a nodes from others */
+ cfg_rc_t
+ cfg_node_unlink(
+ cfg_t *cfg,
+ cfg_node_t *node)
+ {
+ cfg_node_t *n;
+
+ /* argument sanity checking */
+ 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;
+ }
+
|