aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael G. Martins <rafael@rafaelmartins.eng.br>2015-10-24 04:12:43 -0200
committerRafael G. Martins <rafael@rafaelmartins.eng.br>2015-10-24 04:12:43 -0200
commit3a5ea19f35e4228cd782d69f21f52656c1e9a1b8 (patch)
treed587ea7522d51d0d15c63c891a2b4f58e88060a0
parentb3eb6d3f1cae3449c8f988fe0985c58d1e22a7f8 (diff)
downloadblogc-3a5ea19f35e4228cd782d69f21f52656c1e9a1b8.tar.gz
blogc-3a5ea19f35e4228cd782d69f21f52656c1e9a1b8.tar.bz2
blogc-3a5ea19f35e4228cd782d69f21f52656c1e9a1b8.zip
error: improved error reporting for parsers
it will now report the line and the approximate position of the error.
-rw-r--r--src/error.c50
-rw-r--r--tests/check_error.c40
-rw-r--r--tests/check_source_parser.c18
-rw-r--r--tests/check_template_parser.c47
4 files changed, 117 insertions, 38 deletions
diff --git a/src/error.c b/src/error.c
index ad4e3f4..d3d045d 100644
--- a/src/error.c
+++ b/src/error.c
@@ -50,26 +50,54 @@ blogc_error_parser(blogc_error_type_t type, const char *src, size_t src_len,
char *msg = b_strdup_vprintf(format, ap);
va_end(ap);
- b_string_t *str = b_string_new();
- while (current < src_len) {
- char c = src[current];
-
- if (c == '\r' || c == '\n')
+ size_t lineno = 1;
+ size_t linestart = 0;
+ size_t lineend = 0;
+ size_t pos = 1;
+
+ for (size_t i = 0; i < src_len; i++) {
+ char c = src[i];
+ if (i < current) {
+ if ((i + 1) < src_len) {
+ if ((c == '\n' && src[i + 1] == '\r') ||
+ (c == '\r' && src[i + 1] == '\n'))
+ {
+ lineno++;
+ pos = 1;
+ c = src[++i];
+ if ((i + 1) < src_len)
+ linestart = i + 1;
+ continue;
+ }
+ }
+ if (c == '\n' || c == '\r') {
+ lineno++;
+ pos = 1;
+ if ((i + 1) < src_len)
+ linestart = i + 1;
+ continue;
+ }
+ pos++;
+ }
+ else if (c == '\n' || c == '\r') {
+ lineend = i;
break;
+ }
+ }
- b_string_append_c(str, c);
+ if (lineend <= linestart && src_len >= linestart)
+ lineend = src_len;
- current++;
- }
- char *line = b_string_free(str, false);
+ char *line = b_strndup(src + linestart, lineend - linestart);
blogc_error_t *rv = NULL;
- if (strlen(line) == 0) // "near to" message isn't useful if line is empty
+ if (line[0] == '\0') // "near" message isn't useful if line is empty
rv = blogc_error_new(type, msg);
else
rv = blogc_error_new_printf(type,
- "%s\nError occurred near to '%s'", msg, line);
+ "%s\nError occurred near line %d, position %d: %s", msg, lineno,
+ pos, line);
free(msg);
free(line);
diff --git a/tests/check_error.c b/tests/check_error.c
index 68f287a..17e1c40 100644
--- a/tests/check_error.c
+++ b/tests/check_error.c
@@ -48,7 +48,28 @@ test_error_parser(void **state)
blogc_error_t *error = blogc_error_parser(1, a, strlen(a), 11, "asd %d", 10);
assert_non_null(error);
assert_int_equal(error->type, 1);
- assert_string_equal(error->msg, "asd 10\nError occurred near to 'hunda'");
+ assert_string_equal(error->msg,
+ "asd 10\nError occurred near line 3, position 2: chunda");
+ blogc_error_free(error);
+ a = "bola\nguda\nchunda";
+ error = blogc_error_parser(1, a, strlen(a), 11, "asd %d", 10);
+ assert_non_null(error);
+ assert_int_equal(error->type, 1);
+ assert_string_equal(error->msg,
+ "asd 10\nError occurred near line 3, position 2: chunda");
+ blogc_error_free(error);
+ a = "bola\nguda\nchunda";
+ error = blogc_error_parser(1, a, strlen(a), 0, "asd %d", 10);
+ assert_non_null(error);
+ assert_int_equal(error->type, 1);
+ assert_string_equal(error->msg,
+ "asd 10\nError occurred near line 1, position 1: bola");
+ blogc_error_free(error);
+ a = "";
+ error = blogc_error_parser(1, a, strlen(a), 0, "asd %d", 10);
+ assert_non_null(error);
+ assert_int_equal(error->type, 1);
+ assert_string_equal(error->msg, "asd 10");
blogc_error_free(error);
}
@@ -60,7 +81,22 @@ test_error_parser_crlf(void **state)
blogc_error_t *error = blogc_error_parser(1, a, strlen(a), 13, "asd %d", 10);
assert_non_null(error);
assert_int_equal(error->type, 1);
- assert_string_equal(error->msg, "asd 10\nError occurred near to 'hunda'");
+ assert_string_equal(error->msg,
+ "asd 10\nError occurred near line 3, position 2: chunda");
+ blogc_error_free(error);
+ a = "bola\r\nguda\r\nchunda";
+ error = blogc_error_parser(1, a, strlen(a), 13, "asd %d", 10);
+ assert_non_null(error);
+ assert_int_equal(error->type, 1);
+ assert_string_equal(error->msg,
+ "asd 10\nError occurred near line 3, position 2: chunda");
+ blogc_error_free(error);
+ a = "bola\r\nguda\r\nchunda";
+ error = blogc_error_parser(1, a, strlen(a), 0, "asd %d", 10);
+ assert_non_null(error);
+ assert_int_equal(error->type, 1);
+ assert_string_equal(error->msg,
+ "asd 10\nError occurred near line 1, position 1: bola");
blogc_error_free(error);
}
diff --git a/tests/check_source_parser.c b/tests/check_source_parser.c
index 810786b..4d8518e 100644
--- a/tests/check_source_parser.c
+++ b/tests/check_source_parser.c
@@ -183,7 +183,7 @@ test_source_parse_config_invalid_key(void **state)
assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
assert_string_equal(err->msg,
"Can't find a configuration key or the content separator.\n"
- "Error occurred near to 'bola: guda'");
+ "Error occurred near line 1, position 1: bola: guda");
blogc_error_free(err);
b_trie_free(source);
}
@@ -199,7 +199,7 @@ test_source_parse_config_no_key(void **state)
assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
assert_string_equal(err->msg,
"Invalid configuration key.\n"
- "Error occurred near to 'a'");
+ "Error occurred near line 1, position 4: BOLa");
blogc_error_free(err);
b_trie_free(source);
}
@@ -214,7 +214,8 @@ test_source_parse_config_no_key2(void **state)
assert_non_null(err);
assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
assert_string_equal(err->msg,
- "Your last configuration key is missing ':' and the value");
+ "Your last configuration key is missing ':' and the value\n"
+ "Error occurred near line 1, position 5: BOLA");
blogc_error_free(err);
b_trie_free(source);
}
@@ -230,7 +231,8 @@ test_source_parse_config_no_value(void **state)
assert_non_null(err);
assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
assert_string_equal(err->msg,
- "Configuration value not provided for 'BOLA'.");
+ "Configuration value not provided for 'BOLA'.\n"
+ "Error occurred near line 1, position 6: BOLA:");
blogc_error_free(err);
b_trie_free(source);
}
@@ -246,7 +248,8 @@ test_source_parse_config_no_value2(void **state)
assert_non_null(err);
assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
assert_string_equal(err->msg,
- "Configuration value not provided for 'BOLA'.");
+ "Configuration value not provided for 'BOLA'.\n"
+ "Error occurred near line 1, position 6: BOLA:");
blogc_error_free(err);
b_trie_free(source);
}
@@ -449,7 +452,8 @@ test_source_parse_config_value_no_line_ending(void **state)
assert_non_null(err);
assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
assert_string_equal(err->msg,
- "No line ending after the configuration value for 'BOLA'.");
+ "No line ending after the configuration value for 'BOLA'.\n"
+ "Error occurred near line 1, position 10: BOLA: asd");
blogc_error_free(err);
b_trie_free(source);
}
@@ -466,7 +470,7 @@ test_source_parse_invalid_separator(void **state)
assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
assert_string_equal(err->msg,
"Invalid content separator. Must be more than one '-' characters.\n"
- "Error occurred near to '#'");
+ "Error occurred near line 2, position 4: ---#");
blogc_error_free(err);
b_trie_free(source);
}
diff --git a/tests/check_template_parser.c b/tests/check_template_parser.c
index df5dc4c..94f669b 100644
--- a/tests/check_template_parser.c
+++ b/tests/check_template_parser.c
@@ -359,7 +359,7 @@ test_template_parse_invalid_block_start(void **state)
assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
assert_string_equal(err->msg,
"Invalid statement syntax. Must begin with lowercase letter.\n"
- "Error occurred near to 'ASD %}'");
+ "Error occurred near line 1, position 4: {% ASD %}");
blogc_error_free(err);
}
@@ -377,7 +377,7 @@ test_template_parse_invalid_block_nested(void **state)
assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
assert_string_equal(err->msg,
"Blocks can't be nested.\n"
- "Error occurred near to ' listing %}'");
+ "Error occurred near line 2, position 9: {% block listing %}");
blogc_error_free(err);
}
@@ -393,7 +393,7 @@ test_template_parse_invalid_block_not_open(void **state)
assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
assert_string_equal(err->msg,
"'endblock' statement without an open 'block' statement.\n"
- "Error occurred near to ' %}'");
+ "Error occurred near line 1, position 12: {% endblock %}");
blogc_error_free(err);
}
@@ -409,7 +409,8 @@ test_template_parse_invalid_endif_not_open(void **state)
assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
assert_string_equal(err->msg,
"'endif' statement without an open 'ifdef' or 'ifndef' statement.\n"
- "Error occurred near to ' %}{% endblock %}'");
+ "Error occurred near line 1, position 28: "
+ "{% block listing %}{% endif %}{% endblock %}");
blogc_error_free(err);
}
@@ -425,7 +426,8 @@ test_template_parse_invalid_block_name(void **state)
assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
assert_string_equal(err->msg,
"Invalid statement type: Allowed types are: 'block', 'endblock', 'ifdef', "
- "'ifndef' and 'endif'.\nError occurred near to ' %}'");
+ "'ifndef' and 'endif'.\n"
+ "Error occurred near line 1, position 10: {% chunda %}");
blogc_error_free(err);
}
@@ -441,7 +443,7 @@ test_template_parse_invalid_block_type_start(void **state)
assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
assert_string_equal(err->msg,
"Invalid block syntax. Must begin with lowercase letter.\n"
- "Error occurred near to 'ENTRY %}'");
+ "Error occurred near line 1, position 10: {% block ENTRY %}");
blogc_error_free(err);
}
@@ -457,7 +459,7 @@ test_template_parse_invalid_block_type(void **state)
assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
assert_string_equal(err->msg,
"Invalid block type. Allowed types are: 'entry', 'listing' and 'listing_once'.\n"
- "Error occurred near to ' %}'");
+ "Error occurred near line 1, position 16: {% block chunda %}");
blogc_error_free(err);
}
@@ -473,7 +475,8 @@ test_template_parse_invalid_ifdef_start(void **state)
assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
assert_string_equal(err->msg,
"Invalid variable name. Must begin with uppercase letter.\n"
- "Error occurred near to 'guda %}'");
+ "Error occurred near line 1, position 27: "
+ "{% block entry %}{% ifdef guda %}");
blogc_error_free(err);
}
@@ -489,7 +492,8 @@ test_template_parse_invalid_ifdef_variable(void **state)
assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
assert_string_equal(err->msg,
"Invalid variable name. Must be uppercase letter, number or '_'.\n"
- "Error occurred near to 'oLA %}'");
+ "Error occurred near line 1, position 28: "
+ "{% block entry %}{% ifdef BoLA %}");
blogc_error_free(err);
}
@@ -505,7 +509,8 @@ test_template_parse_invalid_if_operator(void **state)
assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
assert_string_equal(err->msg,
"Invalid 'if' operator. Must be '<', '>', '<=', '>=', '==' or '!='.\n"
- "Error occurred near to '= \"asd\" %}'");
+ "Error occurred near line 1, position 29: "
+ "{% block entry %}{% if BOLA = \"asd\" %}");
blogc_error_free(err);
}
@@ -521,7 +526,8 @@ test_template_parse_invalid_if_operand(void **state)
assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
assert_string_equal(err->msg,
"Invalid 'if' operand. Must be double-quoted static string.\n"
- "Error occurred near to 'asd %}'");
+ "Error occurred near line 1, position 32: "
+ "{% block entry %}{% if BOLA == asd %}");
blogc_error_free(err);
}
@@ -537,7 +543,8 @@ test_template_parse_invalid_if_operand2(void **state)
assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
assert_string_equal(err->msg,
"Found an open double-quoted string.\n"
- "Error occurred near to '\"asd %}'");
+ "Error occurred near line 1, position 32: "
+ "{% block entry %}{% if BOLA == \"asd %}");
blogc_error_free(err);
}
@@ -553,7 +560,7 @@ test_template_parse_invalid_block_end(void **state)
assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
assert_string_equal(err->msg,
"Invalid statement syntax. Must end with '%}'.\n"
- "Error occurred near to '}}'");
+ "Error occurred near line 1, position 16: {% block entry }}");
blogc_error_free(err);
}
@@ -569,7 +576,8 @@ test_template_parse_invalid_variable_name(void **state)
assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
assert_string_equal(err->msg,
"Invalid variable name. Must begin with uppercase letter.\n"
- "Error occurred near to 'bola }}{% endblock %}'");
+ "Error occurred near line 1, position 21: "
+ "{% block entry %}{{ bola }}{% endblock %}");
blogc_error_free(err);
}
@@ -585,7 +593,8 @@ test_template_parse_invalid_variable_name2(void **state)
assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
assert_string_equal(err->msg,
"Invalid variable name. Must be uppercase letter, number or '_'.\n"
- "Error occurred near to 'ola }}{% endblock %}'");
+ "Error occurred near line 1, position 22: "
+ "{% block entry %}{{ Bola }}{% endblock %}");
blogc_error_free(err);
}
@@ -601,7 +610,8 @@ test_template_parse_invalid_variable_end(void **state)
assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
assert_string_equal(err->msg,
"Invalid statement syntax. Must end with '}}'.\n"
- "Error occurred near to '%}{% endblock %}'");
+ "Error occurred near line 1, position 26: "
+ "{% block entry %}{{ BOLA %}{% endblock %}");
blogc_error_free(err);
}
@@ -617,7 +627,7 @@ test_template_parse_invalid_close(void **state)
assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
assert_string_equal(err->msg,
"Invalid statement syntax. Must end with '}'.\n"
- "Error occurred near to '%'");
+ "Error occurred near line 1, position 17: {% block entry %%");
blogc_error_free(err);
}
@@ -633,7 +643,8 @@ test_template_parse_invalid_close2(void **state)
assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
assert_string_equal(err->msg,
"Invalid statement syntax. Must end with '}'.\n"
- "Error occurred near to '%{% endblock %}'");
+ "Error occurred near line 1, position 27: "
+ "{% block entry %}{{ BOLA }%{% endblock %}");
blogc_error_free(err);
}