From 9285974bffe15033acc4413c5dd275cd8722466f Mon Sep 17 00:00:00 2001
From: Přemysl Janouch
Date: Fri, 1 May 2015 18:39:38 +0200
Subject: Fix error reporting in configuration parsing
---
common.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 64 insertions(+), 15 deletions(-)
diff --git a/common.c b/common.c
index 5f86396..4b7e6bf 100644
--- a/common.c
+++ b/common.c
@@ -673,16 +673,42 @@ enum config_token
CONFIG_T_STRING ///< CONFIG_ITEM_STRING{,_LIST}
};
+static const char *
+config_token_name (enum config_token token)
+{
+ switch (token)
+ {
+ case CONFIG_T_ABORT: return "end of input";
+
+ case CONFIG_T_WORD: return "word";
+ case CONFIG_T_EQUALS: return "equal sign";
+ case CONFIG_T_LBRACE: return "left brace";
+ case CONFIG_T_RBRACE: return "right brace";
+ case CONFIG_T_NEWLINE: return "newline";
+
+ case CONFIG_T_NULL: return "null value";
+ case CONFIG_T_BOOLEAN: return "boolean";
+ case CONFIG_T_INTEGER: return "integer";
+ case CONFIG_T_STRING: return "string";
+
+ default:
+ hard_assert (!"invalid token value");
+ }
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
struct config_tokenizer
{
- const char *p;
- size_t len;
+ const char *p; ///< Current position in input
+ size_t len; ///< How many bytes of input are left
- unsigned line;
- unsigned column;
+ bool report_line; ///< Whether to count lines at all
+ unsigned line; ///< Current line
+ unsigned column; ///< Current column
- int64_t integer;
- struct str string;
+ int64_t integer; ///< Parsed boolean or integer value
+ struct str string; ///< Parsed string value
};
/// Input has to be null-terminated anyway
@@ -692,6 +718,7 @@ config_tokenizer_init (struct config_tokenizer *self, const char *p, size_t len)
memset (self, 0, sizeof *self);
self->p = p;
self->len = len;
+ self->report_line = true;
str_init (&self->string);
}
@@ -711,7 +738,7 @@ static int
config_tokenizer_advance (struct config_tokenizer *self)
{
int c = *self->p++;
- if (c == '\n')
+ if (c == '\n' && self->report_line)
{
self->column = 0;
self->line++;
@@ -723,13 +750,29 @@ config_tokenizer_advance (struct config_tokenizer *self)
return c;
}
+static void config_tokenizer_error (struct config_tokenizer *self,
+ struct error **e, const char *format, ...) ATTRIBUTE_PRINTF (3, 4);
+
static void
config_tokenizer_error (struct config_tokenizer *self,
- struct error **e, const char *description)
+ struct error **e, const char *format, ...)
{
- // FIXME: we don't always want to specify the line
- error_set (e, "near line %u, column %u: %s",
- self->line + 1, self->column + 1, description);
+ struct str description;
+ str_init (&description);
+
+ va_list ap;
+ va_start (ap, format);
+ str_append_vprintf (&description, format, ap);
+ va_end (ap);
+
+ if (self->report_line)
+ error_set (e, "near line %u, column %u: %s",
+ self->line + 1, self->column + 1, description.str);
+ else
+ error_set (e, "near character %u: %s",
+ self->column + 1, description.str);
+
+ str_free (&description);
}
static enum config_token
@@ -856,9 +899,10 @@ config_parser_expect
if (config_parser_accept (self, token, out))
return;
- // TODO: fill in "X" and "Y"
config_tokenizer_error (&self->tokenizer, &self->error,
- "unexpected X, expected Y");
+ "unexpected `%s', expected `%s'",
+ config_token_name (self->token),
+ config_token_name (token));
longjmp (out, 1);
}
@@ -903,9 +947,9 @@ config_parser_parse_value (struct config_parser *self, jmp_buf out)
if (ACCEPT (CONFIG_T_STRING))
return config_item_string (&self->tokenizer.string);
- // TODO: fill in "X" as the token name
config_tokenizer_error (&self->tokenizer, &self->error,
- "unexpected X, expected a value");
+ "unexpected `%s', expected a value",
+ config_token_name (self->token));
longjmp (out, 1);
}
@@ -1003,7 +1047,12 @@ config_item_parse (const char *script, size_t len,
}
if (single_value_only)
+ {
+ // This is really only intended for in-program configuration
+ // and telling the line number would look awkward
+ parser.tokenizer.report_line = false;
object = config_parser_parse_value (&parser, err);
+ }
else
object = config_parser_parse_object (&parser, err);
config_parser_expect (&parser, CONFIG_T_ABORT, err);
--
cgit v1.2.3-70-g09d2