diff options
-rw-r--r-- | src/template-parser.c | 63 | ||||
-rw-r--r-- | tests/check_template_parser.c | 154 |
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), }; |