aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/format.c5
-rw-r--r--src/grecs.h3
-rw-r--r--src/tree.c80
-rw-r--r--tests/Makefile.am1
-rw-r--r--tests/gcffmt.c12
-rw-r--r--tests/gcfpeek.c2
-rw-r--r--tests/gcfset.c34
-rw-r--r--tests/reduce03.at42
-rw-r--r--tests/testsuite.at1
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 *,
diff --git a/src/tree.c b/src/tree.c
index 955fc52..06f15f0 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -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])

Return to:

Send suggestions and report system problems to the System administrator.