aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/template-parser.c63
-rw-r--r--tests/check_template_parser.c154
2 files changed, 189 insertions, 28 deletions
diff --git a/src/template-parser.c b/src/template-parser.c
index 751fd9e..7e9a444 100644
--- a/src/template-parser.c
+++ b/src/template-parser.c
@@ -44,14 +44,6 @@ typedef enum {
} blogc_template_parser_state_t;
-typedef enum {
- BLOCK_CLOSED = 1,
- BLOCK_ENTRY,
- BLOCK_LISTING,
- BLOCK_LISTING_ONCE,
-} blogc_template_parser_block_state_t;
-
-
sb_slist_t*
blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
{
@@ -69,8 +61,10 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
blogc_template_stmt_operator_t tmp_op = 0;
unsigned int if_count = 0;
+ unsigned int block_if_count = 0;
bool else_open = false;
bool foreach_open = false;
+ bool block_foreach_open = false;
sb_slist_t *stmts = NULL;
blogc_template_stmt_t *stmt = NULL;
@@ -88,11 +82,13 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
bool lstrip_next = false;
char *tmp = NULL;
+ char *block_type = NULL;
blogc_template_parser_state_t state = TEMPLATE_START;
- blogc_template_parser_block_state_t block_state = BLOCK_CLOSED;
blogc_template_stmt_type_t type = BLOGC_TEMPLATE_CONTENT_STMT;
+ bool block_open = false;
+
while (current < src_len) {
char c = src[current];
bool last = current == src_len - 1;
@@ -194,10 +190,12 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
if ((current - start == 5) &&
(0 == strncmp("block", src + start, 5)))
{
- if (block_state == BLOCK_CLOSED) {
+ if (!block_open) {
state = TEMPLATE_BLOCK_BLOCK_TYPE_START;
type = BLOGC_TEMPLATE_BLOCK_STMT;
start = current;
+ block_if_count = if_count;
+ block_foreach_open = foreach_open;
break;
}
*err = blogc_error_parser(BLOGC_ERROR_TEMPLATE_PARSER,
@@ -207,10 +205,23 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
else if ((current - start == 8) &&
(0 == strncmp("endblock", src + start, 8)))
{
- if (block_state != BLOCK_CLOSED) {
+ if (block_open) {
+ if (if_count != block_if_count) {
+ *err = blogc_error_new_printf(BLOGC_ERROR_TEMPLATE_PARSER,
+ "%d open 'if', 'ifdef' and/or 'ifndef' statements "
+ "were not closed inside a '%s' block!",
+ if_count - block_if_count, block_type);
+ break;
+ }
+ if (!block_foreach_open && foreach_open) {
+ *err = blogc_error_new_printf(BLOGC_ERROR_TEMPLATE_PARSER,
+ "An open 'foreach' statement was not closed "
+ "inside a '%s' block!", block_type);
+ break;
+ }
state = TEMPLATE_BLOCK_END_WHITESPACE_CLEANER;
type = BLOGC_TEMPLATE_ENDBLOCK_STMT;
- block_state = BLOCK_CLOSED;
+ block_open = false;
break;
}
*err = blogc_error_parser(BLOGC_ERROR_TEMPLATE_PARSER,
@@ -251,7 +262,9 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
else if ((current - start == 4) &&
(0 == strncmp("else", src + start, 4)))
{
- if (if_count > 0) {
+ if ((block_open && if_count > block_if_count) ||
+ (!block_open && if_count > 0))
+ {
if (!else_open) {
state = TEMPLATE_BLOCK_END_WHITESPACE_CLEANER;
type = BLOGC_TEMPLATE_ELSE_STMT;
@@ -273,7 +286,9 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
else if ((current - start == 5) &&
(0 == strncmp("endif", src + start, 5)))
{
- if (if_count > 0) {
+ if ((block_open && if_count > block_if_count) ||
+ (!block_open && if_count > 0))
+ {
state = TEMPLATE_BLOCK_END_WHITESPACE_CLEANER;
type = BLOGC_TEMPLATE_ENDIF_STMT;
if_count--;
@@ -304,7 +319,9 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
else if ((current - start == 10) &&
(0 == strncmp("endforeach", src + start, 10)))
{
- if (foreach_open) {
+ if ((block_open && !block_foreach_open && foreach_open) ||
+ (!block_open && foreach_open))
+ {
state = TEMPLATE_BLOCK_END_WHITESPACE_CLEANER;
type = BLOGC_TEMPLATE_ENDFOREACH_STMT;
foreach_open = false;
@@ -320,8 +337,8 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
*err = blogc_error_parser(BLOGC_ERROR_TEMPLATE_PARSER, src,
src_len, current,
"Invalid statement type: Allowed types are: 'block', "
- "'endblock', 'ifdef', 'ifndef', 'else', 'endif', 'foreach' "
- "and 'endforeach'.");
+ "'endblock', 'if', 'ifdef', 'ifndef', 'else', 'endif', "
+ "'foreach' and 'endforeach'.");
break;
case TEMPLATE_BLOCK_BLOCK_TYPE_START:
@@ -344,7 +361,7 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
if ((current - start == 5) &&
(0 == strncmp("entry", src + start, 5)))
{
- block_state = BLOCK_ENTRY;
+ block_open = true;
end = current;
state = TEMPLATE_BLOCK_END_WHITESPACE_CLEANER;
break;
@@ -352,7 +369,7 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
else if ((current - start == 7) &&
(0 == strncmp("listing", src + start, 7)))
{
- block_state = BLOCK_LISTING;
+ block_open = true;
end = current;
state = TEMPLATE_BLOCK_END_WHITESPACE_CLEANER;
break;
@@ -360,7 +377,7 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
else if ((current - start == 12) &&
(0 == strncmp("listing_once", src + start, 12)))
{
- block_state = BLOCK_LISTING_ONCE;
+ block_open = true;
end = current;
state = TEMPLATE_BLOCK_END_WHITESPACE_CLEANER;
break;
@@ -598,6 +615,8 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
start2 = 0;
end2 = 0;
}
+ if (type == BLOGC_TEMPLATE_BLOCK_STMT)
+ block_type = stmt->value;
stmts = sb_slist_append(stmts, stmt);
previous = stmt;
stmt = NULL;
@@ -625,9 +644,9 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
start2, "Found an open double-quoted string.");
else if (if_count != 0)
*err = blogc_error_new_printf(BLOGC_ERROR_TEMPLATE_PARSER,
- "%d open 'ifdef' and/or 'ifndef' statements were not closed!",
+ "%d open 'if', 'ifdef' and/or 'ifndef' statements were not closed!",
if_count);
- else if (block_state != BLOCK_CLOSED)
+ else if (block_open)
*err = blogc_error_new(BLOGC_ERROR_TEMPLATE_PARSER,
"An open block was not closed!");
else if (foreach_open)
diff --git a/tests/check_template_parser.c b/tests/check_template_parser.c
index 9669638..2b34c6f 100644
--- a/tests/check_template_parser.c
+++ b/tests/check_template_parser.c
@@ -550,6 +550,40 @@ test_template_parse_invalid_endif_not_open(void **state)
static void
+test_template_parse_invalid_endif_not_open_inside_block(void **state)
+{
+ const char *a = "{% ifdef BOLA %}{% block listing %}{% endif %}{% endblock %}";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "'endif' statement without an open 'if', 'ifdef' or 'ifndef' statement.\n"
+ "Error occurred near line 1, position 44: {% ifdef BOLA %}{% block "
+ "listing %}{% endif %}{% endblock %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_else_not_open_inside_block(void **state)
+{
+ const char *a = "{% ifdef BOLA %}{% block listing %}{% else %}{% endif %}{% endblock %}";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "'else' statement without an open 'if', 'ifdef' or 'ifndef' statement.\n"
+ "Error occurred near line 1, position 43: {% ifdef BOLA %}"
+ "{% block listing %}{% else %}{% endif %}{% endblock %}");
+ blogc_error_free(err);
+}
+
+
+static void
test_template_parse_invalid_endforeach_not_open(void **state)
{
const char *a = "{% endforeach %}\n";
@@ -566,6 +600,74 @@ test_template_parse_invalid_endforeach_not_open(void **state)
static void
+test_template_parse_invalid_endforeach_not_open_inside_block(void **state)
+{
+ const char *a = "{% foreach TAGS %}{% block entry %}{% endforeach %}"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "'endforeach' statement without an open 'foreach' statement.\n"
+ "Error occurred near line 1, position 49: {% foreach TAGS %}"
+ "{% block entry %}{% endforeach %}{% endblock %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_endforeach_not_open_inside_block2(void **state)
+{
+ const char *a = "{% block entry %}{% foreach TAGS %}"
+ "{% endforeach %}{% endforeach %}{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "'endforeach' statement without an open 'foreach' statement.\n"
+ "Error occurred near line 1, position 65: {% block entry %}"
+ "{% foreach TAGS %}{% endforeach %}{% endforeach %}{% endblock %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_endforeach_not_closed_inside_block(void **state)
+{
+ const char *a = "{% block entry %}{% foreach TAGS %}{% endblock %}"
+ "{% endforeach %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "An open 'foreach' statement was not closed inside a 'entry' block!");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_endforeach_not_closed_inside_block2(void **state)
+{
+ const char *a = "{% block entry %}{% foreach TAGS %}{% endforeach %}"
+ "{% foreach TAGS %}{% endblock %}{% endforeach %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "An open 'foreach' statement was not closed inside a 'entry' block!");
+ blogc_error_free(err);
+}
+
+
+static void
test_template_parse_invalid_block_name(void **state)
{
const char *a = "{% chunda %}\n";
@@ -575,8 +677,8 @@ test_template_parse_invalid_block_name(void **state)
assert_null(stmts);
assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
assert_string_equal(err->msg,
- "Invalid statement type: Allowed types are: 'block', 'endblock', 'ifdef', "
- "'ifndef', 'else', 'endif', 'foreach' and 'endforeach'.\n"
+ "Invalid statement type: Allowed types are: 'block', 'endblock', 'if', "
+ "'ifdef', 'ifndef', 'else', 'endif', 'foreach' and 'endforeach'.\n"
"Error occurred near line 1, position 10: {% chunda %}");
blogc_error_free(err);
}
@@ -958,21 +1060,53 @@ test_template_parse_invalid_close2(void **state)
static void
-test_template_parse_invalid_if_not_closed(void **state)
+test_template_parse_invalid_endif_not_closed(void **state)
{
- const char *a = "{% block entry %}{% ifdef BOLA %}{% endblock %}\n";
+ const char *a = "{% block entry %}{% endblock %}{% ifdef BOLA %}\n";
blogc_error_t *err = NULL;
sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
assert_non_null(err);
assert_null(stmts);
assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
- assert_string_equal(err->msg, "1 open 'ifdef' and/or 'ifndef' statements "
+ assert_string_equal(err->msg, "1 open 'if', 'ifdef' and/or 'ifndef' statements "
"were not closed!");
blogc_error_free(err);
}
static void
+test_template_parse_invalid_endif_not_closed_inside_block(void **state)
+{
+ const char *a = "{% block listing %}{% ifdef BOLA %}{% endblock %}{% endif %}";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "1 open 'if', 'ifdef' and/or 'ifndef' statements were not closed inside "
+ "a 'listing' block!");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_else_not_closed_inside_block(void **state)
+{
+ const char *a = "{% block listing %}{% ifdef BOLA %}{% else %}{% endblock %}{% endif %}";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "1 open 'if', 'ifdef' and/or 'ifndef' statements were not closed inside "
+ "a 'listing' block!");
+ blogc_error_free(err);
+}
+
+
+static void
test_template_parse_invalid_block_not_closed(void **state)
{
const char *a = "{% block entry %}\n";
@@ -1014,7 +1148,13 @@ main(void)
unit_test(test_template_parse_invalid_foreach_nested),
unit_test(test_template_parse_invalid_block_not_open),
unit_test(test_template_parse_invalid_endif_not_open),
+ unit_test(test_template_parse_invalid_endif_not_open_inside_block),
+ unit_test(test_template_parse_invalid_else_not_open_inside_block),
unit_test(test_template_parse_invalid_endforeach_not_open),
+ unit_test(test_template_parse_invalid_endforeach_not_open_inside_block),
+ unit_test(test_template_parse_invalid_endforeach_not_open_inside_block2),
+ unit_test(test_template_parse_invalid_endforeach_not_closed_inside_block),
+ unit_test(test_template_parse_invalid_endforeach_not_closed_inside_block2),
unit_test(test_template_parse_invalid_block_name),
unit_test(test_template_parse_invalid_block_type_start),
unit_test(test_template_parse_invalid_block_type),
@@ -1038,7 +1178,9 @@ main(void)
unit_test(test_template_parse_invalid_variable_end),
unit_test(test_template_parse_invalid_close),
unit_test(test_template_parse_invalid_close2),
- unit_test(test_template_parse_invalid_if_not_closed),
+ unit_test(test_template_parse_invalid_endif_not_closed),
+ unit_test(test_template_parse_invalid_endif_not_closed_inside_block),
+ unit_test(test_template_parse_invalid_else_not_closed_inside_block),
unit_test(test_template_parse_invalid_block_not_closed),
unit_test(test_template_parse_invalid_foreach_not_closed),
};