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 @@ -26,25 +26,25 @@ enum grecs_node_type { grecs_node_stmt, grecs_node_block }; typedef struct grecs_node { enum grecs_node_type type; 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; void grecs_node_free(struct grecs_node *node); struct grecs_node *grecs_node_create(enum grecs_node_type type, grecs_locus_t *loc); struct grecs_node *grecs_node_create_points(enum grecs_node_type type, struct grecs_locus_point beg, struct grecs_locus_point end); 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 @@ -58,14 +58,22 @@ struct grecs_node *grecs_match_first(struct grecs_node *tree, const char *pattern, grecs_match_buf_t *buf); struct grecs_node *grecs_match_next(struct grecs_match_buf *buf); void grecs_match_buf_free(struct grecs_match_buf *buf); grecs_match_buf_t grecs_match_buf_create(int argc, char **argv, struct grecs_value **labelv); 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 @@ -35,18 +35,19 @@ typedef struct grecs_value { struct grecs_value **v; } arg; } v; } grecs_value_t; #define GRECS_VALUE_EMPTY_P(val) \ (!(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 @@ -37,24 +37,25 @@ endif if GRECS_COND_GIT_PARSER GRECS_PARSER_GIT = git-parser.c PARSER_DEFS += -DENABLE_GIT_PARSER endif 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\ join.c\ lineacc.c\ list.c\ lookup.c\ mem.c\ opthelp.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 @@ -21,62 +21,62 @@ #include <wordsplit.h> #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> #include <errno.h> 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) { while (level--) fprintf(stream, " "); } void @@ -53,24 +53,37 @@ grecs_value_free_content(struct grecs_value *val) grecs_value_free(val->v.arg.v[i]); free(val->v.arg.v); } } 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) np->locus = *loc; return np; } struct grecs_node * grecs_node_create_points(enum grecs_node_type type, @@ -277,32 +290,50 @@ static struct grecs_keyword fake = { NULL, NULL, grecs_type_void, GRECS_DFLT, NULL, 0, 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; } static void * target_ptr(struct grecs_keyword *kwp, char *base) { if (kwp->varptr) base = (char*) kwp->varptr + kwp->offset; else if (base) @@ -906,39 +937,35 @@ stmt_end(struct nodeproc_closure *clos, struct grecs_node *node) if (kwp) kwp->callback_data = NULL; } static enum grecs_tree_recurse_res 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; } return grecs_tree_recurse_ok; } int grecs_tree_process(struct grecs_node *node, struct grecs_keyword *kwd) @@ -1127,31 +1154,27 @@ node_reduce(struct grecs_node *node, struct grecs_keyword *kwp, int flags) static enum grecs_tree_recurse_res reduceproc(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data) { struct nodeproc_closure *clos = data; if (op == grecs_tree_recurse_post) { 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) { grecs_list_push(clos->sections, clos->cursect); clos->cursect = kwp; } } else if (node_reduce(node, kwp, clos->flags)) return grecs_tree_recurse_skip; } diff --git a/tests/set.at b/tests/set.at index 7daad18..c1cb0b0 100644 --- a/tests/set.at +++ b/tests/set.at @@ -23,16 +23,16 @@ sed 's|^.*/gcf1.conf||' err >&2], [Global settings: scalar = yes listvar = "a" "2" "b" "c" logging: 1/mail/(null)/0 Programs configured: 2 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 |