Index: ossp-pkg/cfg/ChangeLog RCS File: /v/ossp/cvs/ossp-pkg/cfg/ChangeLog,v rcsdiff -q -kk '-r1.19' '-r1.20' -u '/v/ossp/cvs/ossp-pkg/cfg/ChangeLog,v' 2>/dev/null --- ChangeLog 2004/11/20 12:54:07 1.19 +++ ChangeLog 2004/11/20 14:52:56 1.20 @@ -10,6 +10,10 @@ Changes between 0.9.4 and 0.9.5 (31-Oct-2004 to xx-Nov-2004): + *) Change cfg_node_root() API function to be able to both + set and/or get the root node. + [Ralf S. Engelschall ] + *) Fixed cfg_test program by correctly passing the used number of bytes in the buffer instead of the size of the buffer. [Ralf S. Engelschall ] Index: ossp-pkg/cfg/cfg.h RCS File: /v/ossp/cvs/ossp-pkg/cfg/cfg.h,v rcsdiff -q -kk '-r1.14' '-r1.15' -u '/v/ossp/cvs/ossp-pkg/cfg/cfg.h,v' 2>/dev/null --- cfg.h 2004/07/17 07:37:55 1.14 +++ cfg.h 2004/11/20 14:52:56 1.15 @@ -135,7 +135,7 @@ cfg_rc_t cfg_node_get (cfg_t *cfg, cfg_node_t *node, cfg_node_attr_t attr, ...); /* node traversing/locating */ -cfg_rc_t cfg_node_root (cfg_t *cfg, cfg_node_t **node); +cfg_rc_t cfg_node_root (cfg_t *cfg, cfg_node_t *node, cfg_node_t **node_old); cfg_rc_t cfg_node_select (cfg_t *cfg, cfg_node_t *node, cfg_node_t ***result, const char *spec, ...); 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); 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); Index: ossp-pkg/cfg/cfg_node.c RCS File: /v/ossp/cvs/ossp-pkg/cfg/cfg_node.c,v co -q -kk -p'1.21' '/v/ossp/cvs/ossp-pkg/cfg/cfg_node.c,v' | diff -u /dev/null - -L'ossp-pkg/cfg/cfg_node.c' 2>/dev/null --- ossp-pkg/cfg/cfg_node.c +++ - 2024-05-17 17:45:22.021973472 +0200 @@ -0,0 +1,834 @@ +/* +** OSSP cfg - Configuration Parsing +** Copyright (c) 2002-2004 Ralf S. Engelschall +** 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 +#include +#include +#include +#include + +#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")) : "/.."), + (node != NULL ? (node->token != NULL ? node->token : "") : "/..")); + 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")) : "/.."), + (node != NULL ? (node->token != NULL ? node->token : "") : "/..")); + + 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] == '/') { + /* is same as */ + if (node != NULL) + return CFG_ERR_USE; + node = cfg->root; + cp++; + } + else if (node == NULL) { + /* is same as */ + 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; +} + Index: ossp-pkg/cfg/cfg_syn.c RCS File: /v/ossp/cvs/ossp-pkg/cfg/cfg_syn.c,v rcsdiff -q -kk '-r1.19' '-r1.20' -u '/v/ossp/cvs/ossp-pkg/cfg/cfg_syn.c,v' 2>/dev/null --- cfg_syn.c 2004/11/20 12:54:07 1.19 +++ cfg_syn.c 2004/11/20 14:52:56 1.20 @@ -335,7 +335,7 @@ ctx.buf = buf; ctx.indent = 0; - if ((rc = cfg_node_root(cfg, &root)) != CFG_OK) + if ((rc = cfg_node_root(cfg, NULL, &root)) != CFG_OK) return rc; if (node == root) { /* if we dump the whole configuration, treat the first SEQ node special Index: ossp-pkg/cfg/perl/cfg.xs RCS File: /v/ossp/cvs/ossp-pkg/cfg/perl/cfg.xs,v rcsdiff -q -kk '-r1.5' '-r1.6' -u '/v/ossp/cvs/ossp-pkg/cfg/perl/cfg.xs,v' 2>/dev/null --- cfg.xs 2004/11/19 21:37:06 1.5 +++ cfg.xs 2004/11/20 14:52:57 1.6 @@ -396,16 +396,17 @@ RETVAL cfg_rc_t -cfg_node_root(cfg,node) +cfg_node_root(cfg,node,node_old) PROTOTYPE: $$ INPUT: cfg_t *cfg - cfg_node_t *&node = NO_INIT + cfg_node_t *node + cfg_node_t *&node_old = NO_INIT CODE: - RETVAL = cfg_node_root(cfg, &node); + RETVAL = cfg_node_root(cfg, node, &node_old); OUTPUT: - node + node_old RETVAL cfg_rc_t