diff options
-rw-r--r-- | src/format.c | 5 | ||||
-rw-r--r-- | src/grecs.h | 3 | ||||
-rw-r--r-- | src/tree.c | 80 | ||||
-rw-r--r-- | tests/Makefile.am | 1 | ||||
-rw-r--r-- | tests/gcffmt.c | 12 | ||||
-rw-r--r-- | tests/gcfpeek.c | 2 | ||||
-rw-r--r-- | tests/gcfset.c | 34 | ||||
-rw-r--r-- | tests/reduce03.at | 42 | ||||
-rw-r--r-- | tests/testsuite.at | 1 |
9 files changed, 151 insertions, 29 deletions
diff --git a/src/format.c b/src/format.c index f12b465..9b6b6af 100644 --- a/src/format.c +++ b/src/format.c @@ -143,10 +143,11 @@ grecs_format_simple_statement(struct grecs_keyword *kwp, unsigned level, if (GRECS_IS_LIST(kwp->type)) fprintf(stream, "list of %s", gettext(grecs_data_type_string( - GRECS_TYPE (kwp->type)))); + GRECS_TYPE(kwp->type)))); else fprintf(stream, "%s", - gettext(grecs_data_type_string(kwp->type))); + gettext(grecs_data_type_string( + GRECS_TYPE(kwp->type)))); fprintf(stream, ">;\n"); } } diff --git a/src/grecs.h b/src/grecs.h index f32fc1f..628f9f2 100644 --- a/src/grecs.h +++ b/src/grecs.h @@ -338,7 +338,8 @@ int grecs_tree_process(struct grecs_node *node, struct grecs_keyword *kwd); int grecs_value_eq(struct grecs_value *a, struct grecs_value *b); struct grecs_node *grecs_find_node(struct grecs_node *node, const char *path); struct grecs_node *grecs_node_from_path(const char *path, const char *value); -int grecs_tree_reduce(struct grecs_node *node, struct grecs_keyword *kwd); +int grecs_tree_reduce(struct grecs_node *node, struct grecs_keyword *kwd, + int flags); void grecs_tree_sort(struct grecs_node *node, int (*compare)(struct grecs_node const *, @@ -216,7 +216,9 @@ freeproc(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data) int grecs_tree_free(struct grecs_node *node) { - /* FIXME: Check if that's a node_type_root */ + if (!node) + return 0; + /* FIXME: Check if that's a node_type_root */ if (node->type != grecs_node_root) { errno = EINVAL; return 1; @@ -760,6 +762,7 @@ grecs_process_ident(struct grecs_keyword *kwp, grecs_value_t *value, struct nodeproc_closure { struct grecs_keyword *cursect; struct grecs_list *sections; + int flags; }; #define CURRENT_BASE(clos) \ ((char*)((clos)->cursect ? (clos)->cursect->callback_data : NULL)) @@ -900,12 +903,12 @@ value_to_list(struct grecs_value *val) struct grecs_list *list; int i; - if (val->type != GRECS_TYPE_LIST) + if (val->type == GRECS_TYPE_LIST) return; list = grecs_value_list_create(); switch (val->type) { case GRECS_TYPE_STRING: - grecs_list_append(list, val); + grecs_list_append(list, grecs_value_ptr_from_static(val)); break; case GRECS_TYPE_ARRAY: @@ -917,18 +920,63 @@ value_to_list(struct grecs_value *val) } static void +value_to_array(struct grecs_value *val) +{ + if (val->type == GRECS_TYPE_ARRAY) + return; + else { + struct grecs_value **vp; + vp = grecs_calloc(1, sizeof(*vp)); + vp[0] = grecs_value_ptr_from_static(val); + val->type = GRECS_TYPE_ARRAY; + val->v.arg.c = 1; + val->v.arg.v = vp; + } +} + +static void +array_add(struct grecs_value *vx, struct grecs_value *vy) +{ + size_t i; + + vx->v.arg.v = grecs_realloc(vx->v.arg.v, + (vx->v.arg.c + vy->v.arg.c) * + sizeof(vx->v.arg.v[0])); + for (i = 0; i < vy->v.arg.c; i++) + vx->v.arg.v[i + vy->v.arg.c] = vy->v.arg.v[i]; + grecs_free(vy->v.arg.v); + vy->v.arg.v = NULL; + vy->v.arg.c = 0; +} + +static void node_aggregate_stmt(struct grecs_node *dst, struct grecs_node *src, int type) { - value_to_list(dst->v.value); - value_to_list(src->v.value); - grecs_list_add(dst->v.value->v.list, src->v.value->v.list); + if (GRECS_IS_LIST(type)) { + struct grecs_list *t; + /* Coerce both arguments to lists */ + value_to_list(dst->v.value); + value_to_list(src->v.value); + /* Aggregate two lists in order */ + grecs_list_add(src->v.value->v.list, dst->v.value->v.list); + /* Swap them */ + t = dst->v.value->v.list; + dst->v.value->v.list = src->v.value->v.list; + src->v.value->v.list = t; + } else { + value_to_array(dst->v.value); + value_to_array(src->v.value); + array_add(dst->v.value, src->v.value); + } } static void node_merge_stmt(struct grecs_node *to_node, struct grecs_node *from_node, - struct grecs_keyword *kwp) + struct grecs_keyword *kwp, int flags) { - if (kwp && GRECS_IS_LIST(kwp->type) && (kwp->type & GRECS_AGGR)) + if (kwp && + (flags & GRECS_AGGR) ^ (kwp->type & GRECS_AGGR) && + (GRECS_IS_LIST(kwp->type) || kwp->callback)) node_aggregate_stmt(to_node, from_node, kwp->type); else { grecs_value_free(from_node->v.value); @@ -955,7 +1003,7 @@ node_merge_block(struct grecs_node *to_node, struct grecs_node *from_node, } static void -node_reduce(struct grecs_node *node, struct grecs_keyword *kwp) +node_reduce(struct grecs_node *node, struct grecs_keyword *kwp, int flags) { struct grecs_node *p; @@ -967,7 +1015,7 @@ node_reduce(struct grecs_node *node, struct grecs_keyword *kwp) case grecs_node_root: return; case grecs_node_stmt: - node_merge_stmt(p, node, kwp); + node_merge_stmt(p, node, kwp, flags); break; case grecs_node_block: node_merge_block(p, node, kwp); @@ -985,14 +1033,16 @@ reduceproc(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data) if (op == grecs_tree_recurse_post) { if (clos->sections) - grecs_list_pop(clos->sections); + clos->cursect = (struct grecs_keyword *) + grecs_list_pop(clos->sections); } else { struct grecs_keyword *kwp = NULL; if (clos->cursect) { kwp = find_keyword(clos->cursect, node->ident); if (!kwp) { grecs_error(&node->locus, 0, - _("Unknown keyword")); + _("%s: unknown keyword"), + node->ident); return grecs_tree_recurse_skip; } if (op == grecs_tree_recurse_pre) { @@ -1000,13 +1050,14 @@ reduceproc(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data) clos->cursect = kwp; } } - node_reduce(node, kwp); + node_reduce(node, kwp, clos->flags); } return grecs_tree_recurse_ok; } int -grecs_tree_reduce(struct grecs_node *node, struct grecs_keyword *kwd) +grecs_tree_reduce(struct grecs_node *node, struct grecs_keyword *kwd, + int flags) { int rc; struct nodeproc_closure clos; @@ -1020,6 +1071,7 @@ grecs_tree_reduce(struct grecs_node *node, struct grecs_keyword *kwd) clos.cursect = NULL; clos.sections = NULL; } + clos.flags = flags; rc = grecs_tree_recurse(node->down, reduceproc, &clos); grecs_list_free(clos.sections); return rc; diff --git a/tests/Makefile.am b/tests/Makefile.am index e88b689..c2de3e4 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -53,6 +53,7 @@ TESTSUITE_AT = \ reduce00.at\ reduce01.at\ reduce02.at\ + reduce03.at\ set.at\ testsuite.at\ @GRECS_VERCMP_AT@ diff --git a/tests/gcffmt.c b/tests/gcffmt.c index 2097c02..b4a4ece 100644 --- a/tests/gcffmt.c +++ b/tests/gcffmt.c @@ -42,7 +42,7 @@ main(int argc, char **argv) { char *progname = argv[0]; char *file = NULL; - struct grecs_node *tree, *node; + struct grecs_node *tree; int flags = GRECS_NODE_FLAG_DEFAULT; int reduce = 0; int sort = 0; @@ -77,7 +77,7 @@ main(int argc, char **argv) for (; argc; argc--) { char *arg = *++argv; - node = grecs_parse(arg); + struct grecs_node *node = grecs_parse(arg); if (!node) exit(1); if (grecs_tree_join(tree, node)) { @@ -88,13 +88,11 @@ main(int argc, char **argv) } if (reduce) - grecs_tree_reduce(tree, NULL); + grecs_tree_reduce(tree, NULL, 0); if (sort) grecs_tree_sort(tree, node_ident_cmp); - for (node = tree; node; node = node->next) { - grecs_format_node(node, flags, stdout); - fputc('\n', stdout); - } + grecs_format_node(tree, flags, stdout); + fputc('\n', stdout); grecs_tree_free(tree); exit(0); } diff --git a/tests/gcfpeek.c b/tests/gcfpeek.c index 5ff8583..df01b3c 100644 --- a/tests/gcfpeek.c +++ b/tests/gcfpeek.c @@ -69,7 +69,7 @@ main(int argc, char **argv) if (!tree) exit(1); if (reduce) - grecs_tree_reduce(tree, NULL); + grecs_tree_reduce(tree, NULL, 0); for (node = tree; node; node = node->next) { node = grecs_find_node(node, path); diff --git a/tests/gcfset.c b/tests/gcfset.c index f41d67f..1534312 100644 --- a/tests/gcfset.c +++ b/tests/gcfset.c @@ -70,7 +70,7 @@ static struct grecs_keyword logging_kwtab[] = { grecs_type_bool, NULL, offsetof(struct logging_setup, use_syslog) }, { "facility", "name", "Set logging facility", - grecs_type_string, NULL, + grecs_type_string|GRECS_AGGR, NULL, offsetof(struct logging_setup, facility), cb_logging_facility }, { "tag", "label", "Tag logging messages with this string", grecs_type_string, NULL, @@ -167,11 +167,16 @@ print_program(struct program *prog) print_logging_setup(&prog->logging_setup); } +static int +node_ident_cmp(struct grecs_node const *a, struct grecs_node const *b) +{ + return strcmp(a->ident, b->ident); +} static void usage(const char *arg, FILE *fp, int code) { - fprintf(fp, "usage: %s [-h] [-cfhelp] [-reduce] file\n", arg); + fprintf(fp, "usage: %s [-h] [-cfhelp] [-reduce] [-sort] [-print] [-locus] [-noset] file\n", arg); exit(code); } @@ -183,6 +188,10 @@ main(int argc, char **argv) struct grecs_node *tree; int cfhelp = 0; int reduce = 0; + int print = 0; + int sort = 0; + int flags = GRECS_NODE_FLAG_DEFAULT; + int dontset = 0; while (--argc) { char *arg = *++argv; @@ -192,6 +201,16 @@ main(int argc, char **argv) usage(progname, stdout, 0); else if (strcmp(arg, "-reduce") == 0) reduce = 1; + else if (strcmp(arg, "-print") == 0) + print = 1; + else if (strcmp(arg, "-locus") == 0) + flags |= GRECS_NODE_FLAG_LOCUS; + else if (strncmp(arg, "-delim=", 7) == 0) + flags |= arg[7]; + else if (strcmp(arg, "-sort") == 0) + sort = 1; + else if (strcmp(arg, "-noset") == 0) + dontset = 1; else if (arg[0] == '-') usage(progname, stderr, 1); else if (file) @@ -215,8 +234,15 @@ main(int argc, char **argv) if (!tree) exit(2); if (reduce) - grecs_tree_reduce(tree, main_kwtab); - + grecs_tree_reduce(tree, main_kwtab, GRECS_AGGR); + if (sort) + grecs_tree_sort(tree, node_ident_cmp); + if (print) { + grecs_format_node(tree, flags, stdout); + fputc('\n', stdout); + } + if (dontset) + exit(0); if (grecs_tree_process(tree, main_kwtab)) exit(2); grecs_tree_free(tree); diff --git a/tests/reduce03.at b/tests/reduce03.at new file mode 100644 index 0000000..276bbc8 --- /dev/null +++ b/tests/reduce03.at @@ -0,0 +1,42 @@ +# This file is part of grecs -*- Autotest -*- +# Copyright (C) 2007, 2009-2011 Sergey Poznyakoff +# +# Grecs is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# Grecs is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Grecs. If not, see <http://www.gnu.org/licenses/>. + +AT_SETUP([Reduction: table driven]) +AT_KEYWORDS([reduce reduce03]) + +GRECS_TEST([ +scalar bar; +listvar (1, 2); +listvar foo; +logging { + facility local1; + tag prog; +} +listvar (3, 4); +scalar baz; +logging { + facility mail; +} +], +[gcfset -reduce], +[0], +[Global settings: +scalar = baz +listvar = "1" "2" "foo" "3" "4" +logging: 0/mail/prog/0 +]) + +AT_CLEANUP diff --git a/tests/testsuite.at b/tests/testsuite.at index b31eeef..4bbf608 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -60,6 +60,7 @@ m4_include([set.at]) m4_include([reduce00.at]) m4_include([reduce01.at]) m4_include([reduce02.at]) +m4_include([reduce03.at]) m4_include([join.at]) |