diff options
-rw-r--r-- | include/grecs/node.h | 2 | ||||
-rw-r--r-- | include/grecs/tree.h | 8 | ||||
-rw-r--r-- | include/grecs/value.h | 1 | ||||
-rw-r--r-- | src/Make.am | 1 | ||||
-rw-r--r-- | src/assert.c | 58 | ||||
-rw-r--r-- | src/format.c | 22 | ||||
-rw-r--r-- | src/tree.c | 63 | ||||
-rw-r--r-- | tests/set.at | 4 |
8 files changed, 125 insertions, 34 deletions
diff --git a/include/grecs/node.h b/include/grecs/node.h index 2d879ad..752b002 100644 --- a/include/grecs/node.h +++ b/include/grecs/node.h @@ -32,13 +32,13 @@ typedef struct grecs_node { grecs_locus_t locus; struct grecs_node *up; struct grecs_node *down; struct grecs_node *next; struct grecs_node *prev; char *ident; - grecs_locus_t idloc; + grecs_locus_t idloc; /* Location of the identifier */ union { grecs_value_t *value; grecs_symtab_ptr_t texttab; } v; } grecs_node_t; diff --git a/include/grecs/tree.h b/include/grecs/tree.h index 2fb26dd..f13a74b 100644 --- a/include/grecs/tree.h +++ b/include/grecs/tree.h @@ -64,8 +64,16 @@ grecs_match_buf_t grecs_match_buf_create(int argc, char **argv, struct grecs_node *grecs_match_buf_first(struct grecs_match_buf *buf, struct grecs_node *tree); struct grecs_node *grecs_match_buf_get_node(grecs_match_buf_t buf); size_t grecs_match_buf_get_args(grecs_match_buf_t buf, char ***argv); struct grecs_node *grecs_match_buf_get_root(grecs_match_buf_t buf); void grecs_match_buf_set_root(grecs_match_buf_t buf, struct grecs_node *root); + +/* Assertions */ +int grecs_assert_value_type(const grecs_value_t *value, int type, + grecs_locus_t *refloc); +int grecs_assert_scalar_stmt(grecs_locus_t *locus, + enum grecs_callback_command cmd); +int grecs_assert_node_value_type(enum grecs_callback_command cmd, + grecs_node_t *node, int type); #endif diff --git a/include/grecs/value.h b/include/grecs/value.h index 8cd2800..480db9d 100644 --- a/include/grecs/value.h +++ b/include/grecs/value.h @@ -41,12 +41,13 @@ typedef struct grecs_value { (!(val) || \ ((val)->type == GRECS_TYPE_STRING && (val)->v.string == NULL)) void grecs_value_free(struct grecs_value *val); void grecs_value_free_content(struct grecs_value *val); grecs_value_t *grecs_value_ptr_from_static(grecs_value_t *input); +const char *grecs_value_type_string(int t); int grecs_value_eq(struct grecs_value *a, struct grecs_value *b); int grecs_value_match(struct grecs_value *pat, struct grecs_value *b, int flags); #endif diff --git a/src/Make.am b/src/Make.am index 227973e..9fa7688 100644 --- a/src/Make.am +++ b/src/Make.am @@ -43,12 +43,13 @@ if GRECS_COND_JSON GRECS_JSON = json-gram.y json-lex.l jsonfmt.c GRECS_EXTRA_JSON = json-gram.h endif GRECS_SRC = \ asprintf.c\ + assert.c\ cidr.c\ diag.c\ format.c\ grecs-gram.y\ grecs-lex.l\ ipstr.c\ diff --git a/src/assert.c b/src/assert.c new file mode 100644 index 0000000..0577768 --- /dev/null +++ b/src/assert.c @@ -0,0 +1,58 @@ +/* grecs - Gray's Extensible Configuration System + Copyright (C) 2007-2019 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 of the License, 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/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <errno.h> +#include <grecs.h> + +int +grecs_assert_value_type(const grecs_value_t *value, int type, + grecs_locus_t *refloc) +{ + if (GRECS_VALUE_EMPTY_P(value)) { + grecs_error(refloc, 0, _("expected %s"), + gettext(grecs_value_type_string(type))); + return 1; + } + if (value->type != type) { + grecs_error(&value->locus, 0, _("expected %s, but found %s"), + gettext(grecs_value_type_string(type)), + gettext(grecs_value_type_string(value->type))); + return 1; + } + return 0; +} + +int +grecs_assert_scalar_stmt(grecs_locus_t *locus, enum grecs_callback_command cmd) +{ + if (cmd != grecs_callback_set_value) { + grecs_error(locus, 0, _("unexpected block statement")); + return 1; + } + return 0; +} + +int +grecs_assert_node_value_type(enum grecs_callback_command cmd, + grecs_node_t *node, int type) +{ + return grecs_assert_scalar_stmt(&node->locus, cmd) + && grecs_assert_value_type(node->v.value, type, + &node->locus); +} diff --git a/src/format.c b/src/format.c index af87329..d7cdb0f 100644 --- a/src/format.c +++ b/src/format.c @@ -27,50 +27,50 @@ const char * grecs_data_type_string(enum grecs_data_type type) { switch (type) { case grecs_type_void: - return "void"; + return N_("void"); case grecs_type_string: - return "string"; + return N_("string"); case grecs_type_short: case grecs_type_ushort: case grecs_type_int: case grecs_type_uint: case grecs_type_long: case grecs_type_ulong: case grecs_type_size: /*FIXME case grecs_type_off:*/ - return "number"; + return N_("number"); case grecs_type_time: - return "time"; + return N_("time"); case grecs_type_bool: - return "boolean"; + return N_("boolean"); case grecs_type_ipv4: - return "IPv4"; + return N_("IPv4"); case grecs_type_cidr: - return "CIDR"; + return N_("CIDR"); case grecs_type_host: - return "hostname"; + return N_("hostname"); case grecs_type_sockaddr: - return "sockaddr"; + return N_("sockaddr"); case grecs_type_section: - return "section"; + return N_("section"); case grecs_type_null: - return "null"; + return N_("null"); } return "UNKNOWN?"; } static void format_level(unsigned level, FILE *stream) @@ -59,12 +59,25 @@ void grecs_value_free(struct grecs_value *val) { grecs_value_free_content(val); grecs_free(val); } +const char * +grecs_value_type_string(int t) +{ + static const char *types[] = { + [GRECS_TYPE_STRING] = N_("string"), + [GRECS_TYPE_LIST] = N_("list"), + [GRECS_TYPE_ARRAY] = N_("one or more arguments") + }; + if (t >= 0 && t < sizeof(types) / sizeof(types[0])) + return types[t]; + return N_("unrecognized type; please report"); +} + struct grecs_node * grecs_node_create(enum grecs_node_type type, grecs_locus_t *loc) { struct grecs_node *np = grecs_zalloc(sizeof(*np)); np->type = type; if (loc) @@ -283,20 +296,38 @@ static struct grecs_keyword fake = { fake_callback, NULL, &fake }; static struct grecs_keyword * -find_keyword(struct grecs_keyword *cursect, const char *ident) +find_keyword(struct grecs_keyword *cursect, grecs_node_t *node) { - struct grecs_keyword *kwp; - if (cursect && cursect->kwd && cursect != &fake) { - for (kwp = cursect->kwd; kwp->ident; kwp++) - if (strcmp(kwp->ident, ident) == 0) - return kwp; + struct grecs_keyword *found = NULL, *kwp; + char const *msg; + + for (kwp = cursect->kwd; kwp->ident; kwp++) { + if (strcmp(kwp->ident, node->ident) == 0) { + found = kwp; + if (kwp->callback + || node->down + ? kwp->type == grecs_type_section + : kwp->type != grecs_type_section) + return kwp; + } + } + if (found) { + if (found->type == grecs_type_section) { + msg = N_("section keyword used as a scalar"); + } else { + msg = N_("scalar keyword used as a section"); + } + } else { + msg = N_("unknown keyword"); + } + grecs_error(&node->idloc, 0, "%s", gettext(msg)); } else { return &fake; } return NULL; } @@ -912,27 +943,23 @@ nodeproc(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data) { struct nodeproc_closure *clos = data; struct grecs_keyword *kwp; switch (op) { case grecs_tree_recurse_set: - kwp = find_keyword(clos->cursect, node->ident); - if (!kwp) { - grecs_error(&node->idloc, 0, _("Unknown keyword")); + kwp = find_keyword(clos->cursect, node); + if (!kwp) return grecs_tree_recurse_skip; - } grecs_process_ident(kwp, node->v.value, CURRENT_BASE(clos), &node->idloc); break; case grecs_tree_recurse_pre: - kwp = find_keyword(clos->cursect, node->ident); - if (!kwp) { - grecs_error(&node->locus, 0, _("Unknown keyword")); + kwp = find_keyword(clos->cursect, node); + if (!kwp) return grecs_tree_recurse_skip; - } stmt_begin(clos, kwp, node); break; case grecs_tree_recurse_post: stmt_end(clos, node); break; @@ -1133,19 +1160,15 @@ reduceproc(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data) if (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, - _("%s: unknown keyword"), - node->ident); + kwp = find_keyword(clos->cursect, node); + if (!kwp) return grecs_tree_recurse_skip; - } if (kwp->flags & GRECS_INAC) return grecs_tree_recurse_skip; if (!(kwp->flags & GRECS_MULT) && node_reduce(node, kwp, clos->flags)) return grecs_tree_recurse_skip; if (op == grecs_tree_recurse_pre) { diff --git a/tests/set.at b/tests/set.at index 7daad18..c1cb0b0 100644 --- a/tests/set.at +++ b/tests/set.at @@ -29,10 +29,10 @@ Program foo: scalar = no logging: 1/local1/(null)/0 Program bar: scalar = 25 logging: 0/local2/baz/0 ], -[:25.1-8: Unknown keyword +[:25.1-8: unknown keyword ]) -AT_CLEANUP
\ No newline at end of file +AT_CLEANUP |