summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org>2019-06-05 13:42:37 (GMT)
committer Sergey Poznyakoff <gray@gnu.org>2019-06-05 13:52:58 (GMT)
commit806485a57fb37784e3e1789fce829a2bac390d99 (patch) (side-by-side diff)
tree963e02852aa0203c912b9947eec0211e8661bc82
parentf7b04cc09b26a7e1342170129dacf896f50f98b2 (diff)
downloadgrecs-806485a57fb37784e3e1789fce829a2bac390d99.tar.gz
grecs-806485a57fb37784e3e1789fce829a2bac390d99.tar.bz2
Fix syntax checking of compound vs. scalar statements. Add assertion functions.
Up to now the parser incorrectly accepted the use of compound statement keyword in scalar context, unless the keyword description had non NULL value in the callback field. This change fixes it. It also defines several assertion functions for use inm callbacks. * src/tree.c (grecs_value_type_string): New function. (find_keyword): Take into account node type. (nodeproc,reduceproc): Leave error reporting to find_keyword. * tests/set.at: Change expected error string. * include/grecs/tree.h (grecs_assert_value_type) (grecs_assert_scalar_stmt) (grecs_assert_node_value_type): New protos. * include/grecs/value.h (grecs_value_type_string): New proto. * src/Make.am: Add assert.c * src/assert.c: New file. * src/format.c (grecs_data_type_string): Add i18n markers to the returned strings.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--include/grecs/node.h2
-rw-r--r--include/grecs/tree.h8
-rw-r--r--include/grecs/value.h1
-rw-r--r--src/Make.am1
-rw-r--r--src/assert.c58
-rw-r--r--src/format.c22
-rw-r--r--src/tree.c63
-rw-r--r--tests/set.at4
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
@@ -35,7 +35,7 @@ typedef struct grecs_node {
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;
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
@@ -67,5 +67,13 @@ 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
@@ -44,6 +44,7 @@ typedef struct grecs_value {
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,
diff --git a/src/Make.am b/src/Make.am
index 227973e..9fa7688 100644
--- a/src/Make.am
+++ b/src/Make.am
@@ -46,6 +46,7 @@ endif
GRECS_SRC = \
asprintf.c\
+ assert.c\
cidr.c\
diag.c\
format.c\
diff --git a/src/assert.c b/src/assert.c
new file mode 100644
index 0000000..0577768
--- a/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
@@ -30,10 +30,10 @@ 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:
@@ -43,31 +43,31 @@ grecs_data_type_string(enum grecs_data_type type)
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?";
}
diff --git a/src/tree.c b/src/tree.c
index e25c6a5..27a6f21 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -62,6 +62,19 @@ grecs_value_free(struct grecs_value *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)
{
@@ -286,14 +299,32 @@ static struct grecs_keyword 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;
}
@@ -915,21 +946,17 @@ nodeproc(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data)
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;
@@ -1136,13 +1163,9 @@ reduceproc(enum grecs_tree_recurse_op op, struct grecs_node *node, void *data)
} 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) &&
diff --git a/tests/set.at b/tests/set.at
index 7daad18..c1cb0b0 100644
--- a/tests/set.at
+++ b/tests/set.at
@@ -32,7 +32,7 @@ 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

Return to:

Send suggestions and report system problems to the System administrator.