diff options
-rw-r--r-- | src/template-parser.c | 136 | ||||
-rw-r--r-- | src/template-parser.h | 3 | ||||
-rw-r--r-- | tests/check_renderer.c | 14 | ||||
-rw-r--r-- | tests/check_template_parser.c | 41 |
4 files changed, 171 insertions, 23 deletions
diff --git a/src/template-parser.c b/src/template-parser.c index d25ea0f..6eb65b6 100644 --- a/src/template-parser.c +++ b/src/template-parser.c @@ -25,8 +25,12 @@ typedef enum { TEMPLATE_BLOCK_TYPE, TEMPLATE_BLOCK_BLOCK_TYPE_START, TEMPLATE_BLOCK_BLOCK_TYPE, - TEMPLATE_BLOCK_IFDEF_START, - TEMPLATE_BLOCK_IFDEF_VARIABLE, + TEMPLATE_BLOCK_IF_START, + TEMPLATE_BLOCK_IF_VARIABLE, + TEMPLATE_BLOCK_IF_OPERATOR_START, + TEMPLATE_BLOCK_IF_OPERATOR, + TEMPLATE_BLOCK_IF_OPERAND_START, + TEMPLATE_BLOCK_IF_OPERAND, TEMPLATE_BLOCK_END, TEMPLATE_VARIABLE_START, TEMPLATE_VARIABLE, @@ -52,6 +56,10 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err) size_t current = 0; size_t start = 0; size_t end = 0; + size_t op_start = 0; + size_t op_end = 0; + size_t start2 = 0; + size_t end2 = 0; unsigned int if_count = 0; @@ -73,6 +81,8 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err) stmt = b_malloc(sizeof(blogc_template_stmt_t)); stmt->type = type; stmt->value = b_strndup(src + start, src_len - start); + stmt->op = NULL; + stmt->value2 = NULL; stmts = b_slist_append(stmts, stmt); stmt = NULL; } @@ -92,6 +102,8 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err) stmt = b_malloc(sizeof(blogc_template_stmt_t)); stmt->type = type; stmt->value = b_strndup(src + start, end - start); + stmt->op = NULL; + stmt->value2 = NULL; stmts = b_slist_append(stmts, stmt); stmt = NULL; } @@ -117,7 +129,9 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err) if (c >= 'a' && c <= 'z') break; if (c == ' ') { - if (0 == strncmp("block", src + start, current - start)) { + if ((current - start == 5) && + (0 == strncmp("block", src + start, current - start))) + { if (block_state == BLOCK_CLOSED) { state = TEMPLATE_BLOCK_BLOCK_TYPE_START; type = BLOGC_TEMPLATE_BLOCK_STMT; @@ -128,7 +142,9 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err) src, src_len, current, "Blocks can't be nested."); break; } - else if (0 == strncmp("endblock", src + start, current - start)) { + else if ((current - start == 8) && + (0 == strncmp("endblock", src + start, current - start))) + { if (block_state != BLOCK_CLOSED) { state = TEMPLATE_BLOCK_END; type = BLOGC_TEMPLATE_ENDBLOCK_STMT; @@ -140,21 +156,36 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err) "'endblock' statement without an open 'block' statement."); break; } - else if (0 == strncmp("ifdef", src + start, current - start)) { - state = TEMPLATE_BLOCK_IFDEF_START; + else if ((current - start == 5) && + (0 == strncmp("ifdef", src + start, current - start))) + { + state = TEMPLATE_BLOCK_IF_START; type = BLOGC_TEMPLATE_IFDEF_STMT; start = current; if_count++; break; } - else if (0 == strncmp("ifndef", src + start, current - start)) { - state = TEMPLATE_BLOCK_IFDEF_START; + else if ((current - start == 6) && + (0 == strncmp("ifndef", src + start, current - start))) + { + state = TEMPLATE_BLOCK_IF_START; type = BLOGC_TEMPLATE_IFNDEF_STMT; start = current; if_count++; break; } - else if (0 == strncmp("endif", src + start, current - start)) { + else if ((current - start == 2) && + (0 == strncmp("if", src + start, current - start))) + { + state = TEMPLATE_BLOCK_IF_START; + type = BLOGC_TEMPLATE_IF_STMT; + start = current; + if_count++; + break; + } + else if ((current - start == 5) && + (0 == strncmp("endif", src + start, current - start))) + { if (if_count > 0) { state = TEMPLATE_BLOCK_END; type = BLOGC_TEMPLATE_ENDIF_STMT; @@ -216,11 +247,11 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err) "and 'listing_once'."); break; - case TEMPLATE_BLOCK_IFDEF_START: + case TEMPLATE_BLOCK_IF_START: if (c == ' ') break; if (c >= 'A' && c <= 'Z') { - state = TEMPLATE_BLOCK_IFDEF_VARIABLE; + state = TEMPLATE_BLOCK_IF_VARIABLE; start = current; break; } @@ -229,12 +260,15 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err) "Invalid variable name. Must begin with uppercase letter."); break; - case TEMPLATE_BLOCK_IFDEF_VARIABLE: + case TEMPLATE_BLOCK_IF_VARIABLE: if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_') break; if (c == ' ') { end = current; - state = TEMPLATE_BLOCK_END; + if (type == BLOGC_TEMPLATE_IF_STMT) + state = TEMPLATE_BLOCK_IF_OPERATOR_START; + else + state = TEMPLATE_BLOCK_END; break; } *err = blogc_error_parser(BLOGC_ERROR_TEMPLATE_PARSER, src, @@ -243,6 +277,45 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err) "or '_'."); break; + case TEMPLATE_BLOCK_IF_OPERATOR_START: + if (c == ' ') { + break; + } + state = TEMPLATE_BLOCK_IF_OPERATOR; + op_start = current; + break; + + case TEMPLATE_BLOCK_IF_OPERATOR: + if (c != ' ') + break; + state = TEMPLATE_BLOCK_IF_OPERAND_START; + op_end = current; + break; + + case TEMPLATE_BLOCK_IF_OPERAND_START: + if (c == ' ') + break; + if (c != '"') { + op_start = 0; + op_end = 0; + *err = blogc_error_parser(BLOGC_ERROR_TEMPLATE_PARSER, src, + src_len, current, + "Invalid 'if' operand. Must be double-quoted static string."); + break; + } + state = TEMPLATE_BLOCK_IF_OPERAND; + start2 = current + 1; + break; + + case TEMPLATE_BLOCK_IF_OPERAND: + if (c != '"') + break; + if (c == '"' && src[current - 1] == '\\') + break; + state = TEMPLATE_BLOCK_END; + end2 = current; + break; + case TEMPLATE_BLOCK_END: if (c == ' ') break; @@ -302,11 +375,44 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err) case TEMPLATE_CLOSE_BRACKET: if (c == '}') { + if (op_end > op_start) { + if ((!((op_end - op_start == 1) && + (0 == strncmp("<", src + op_start, op_end - op_start)))) && + (!((op_end - op_start == 1) && + (0 == strncmp(">", src + op_start, op_end - op_start)))) && + (!((op_end - op_start == 2) && + (0 == strncmp("<=", src + op_start, op_end - op_start)))) && + (!((op_end - op_start == 2) && + (0 == strncmp(">=", src + op_start, op_end - op_start)))) && + (!((op_end - op_start == 2) && + (0 == strncmp("==", src + op_start, op_end - op_start)))) && + (!((op_end - op_start == 2) && + (0 == strncmp("!=", src + op_start, op_end - op_start))))) + { + *err = blogc_error_parser(BLOGC_ERROR_TEMPLATE_PARSER, + src, src_len, op_start, + "Invalid 'if' operator. Must be '<', '>', " + "'<=', '>=', '==' or '!='."); + break; + } + } stmt = b_malloc(sizeof(blogc_template_stmt_t)); stmt->type = type; stmt->value = NULL; + stmt->op = NULL; + stmt->value2 = NULL; + if (op_end > op_start) { + stmt->op = b_strndup(src + op_start, op_end - op_start); + op_start = 0; + op_end = 0; + } if (end > start) stmt->value = b_strndup(src + start, end - start); + if (end2 > start2) { + stmt->value2 = b_strndup(src + start2, end2 - start2); + start2 = 0; + end2 = 0; + } stmts = b_slist_append(stmts, stmt); stmt = NULL; state = TEMPLATE_START; @@ -355,7 +461,11 @@ blogc_template_free_stmts(b_slist_t *stmts) { for (b_slist_t *tmp = stmts; tmp != NULL; tmp = tmp->next) { blogc_template_stmt_t *data = tmp->data; + if (data == NULL) + continue; free(data->value); + free(data->op); + free(data->value2); free(data); } b_slist_free(stmts); diff --git a/src/template-parser.h b/src/template-parser.h index 88c9ccf..b9213e2 100644 --- a/src/template-parser.h +++ b/src/template-parser.h @@ -15,6 +15,7 @@ typedef enum { BLOGC_TEMPLATE_IFDEF_STMT = 1, BLOGC_TEMPLATE_IFNDEF_STMT, + BLOGC_TEMPLATE_IF_STMT, BLOGC_TEMPLATE_ENDIF_STMT, BLOGC_TEMPLATE_BLOCK_STMT, BLOGC_TEMPLATE_ENDBLOCK_STMT, @@ -25,6 +26,8 @@ typedef enum { typedef struct { blogc_template_stmt_type_t type; char *value; + char *value2; + char *op; } blogc_template_stmt_t; b_slist_t* blogc_template_parse(const char *src, size_t src_len, diff --git a/tests/check_renderer.c b/tests/check_renderer.c index 0244e30..e238610 100644 --- a/tests/check_renderer.c +++ b/tests/check_renderer.c @@ -63,9 +63,9 @@ test_render_entry(void **state) "{% block listing_once %}fuuu{% endblock %}\n" "{% block entry %}\n" "{{ DATE }}\n" - "{% if DATE_FORMATTED %}{{ DATE_FORMATTED }}{% endif %}\n" - "{% if GUDA %}{{ GUDA }}{% endif %}\n" - "{% if CHUNDA %}{{ CHUNDA }}{% endif %}\n" + "{% ifdef DATE_FORMATTED %}{{ DATE_FORMATTED }}{% endif %}\n" + "{% ifdef GUDA %}{{ GUDA }}{% endif %}\n" + "{% ifdef CHUNDA %}{{ CHUNDA }}{% endif %}\n" "{% endblock %}\n" "{% block listing %}lol{% endblock %}\n"; blogc_error_t *err = NULL; @@ -98,12 +98,12 @@ test_render_listing(void **state) "foo\n" "{% block listing_once %}fuuu{% endblock %}\n" "{% block entry %}\n" - "{% if GUDA %}{{ GUDA }}{% endif %}\n" - "{% if CHUNDA %}{{ CHUNDA }}{% endif %}\n" + "{% ifdef GUDA %}{{ GUDA }}{% endif %}\n" + "{% ifdef CHUNDA %}{{ CHUNDA }}{% endif %}\n" "{% endblock %}\n" "{% block listing %}\n" - "{% if DATE_FORMATTED %}{{ DATE_FORMATTED }}{% endif %}\n" - "bola: {% if BOLA %}{{ BOLA }}{% endif %}\n" + "{% ifdef DATE_FORMATTED %}{{ DATE_FORMATTED }}{% endif %}\n" + "bola: {% ifdef BOLA %}{{ BOLA }}{% endif %}\n" "{% endblock %}\n"; blogc_error_t *err = NULL; b_slist_t *l = blogc_template_parse(str, strlen(str), &err); diff --git a/tests/check_template_parser.c b/tests/check_template_parser.c index 3479ca5..06161a7 100644 --- a/tests/check_template_parser.c +++ b/tests/check_template_parser.c @@ -34,6 +34,18 @@ blogc_assert_template_stmt(b_slist_t *l, const char *value, static void +blogc_assert_template_if_stmt(b_slist_t *l, const char *variable, + const char *operator, const char *operand) +{ + blogc_template_stmt_t *stmt = l->data; + assert_string_equal(stmt->value, variable); + assert_string_equal(stmt->op, operator); + assert_string_equal(stmt->value2, operand); + assert_int_equal(stmt->type, BLOGC_TEMPLATE_IF_STMT); +} + + +static void test_template_parse(void **state) { const char *a = @@ -48,7 +60,8 @@ test_template_parse(void **state) "{% endif %}\n" "{% endblock %}\n" "{% block listing %}{{ BOLA }}{% endblock %}\n" - "{% block listing_once %}asd{% endblock %}\n"; + "{% block listing_once %}asd{% endblock %}\n" + "{% if BOLA == \"10\" %}aee{% endif %}"; blogc_error_t *err = NULL; b_slist_t *stmts = blogc_template_parse(a, strlen(a), &err); assert_null(err); @@ -92,7 +105,12 @@ test_template_parse(void **state) NULL, BLOGC_TEMPLATE_ENDBLOCK_STMT); blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next->next->next, "\n", BLOGC_TEMPLATE_CONTENT_STMT); - assert_null(tmp->next->next->next->next->next->next->next->next->next->next); + tmp = tmp->next->next->next->next->next->next->next->next->next->next; + blogc_assert_template_if_stmt(tmp, "BOLA", "==", "10"); + blogc_assert_template_stmt(tmp->next, "aee", BLOGC_TEMPLATE_CONTENT_STMT); + blogc_assert_template_stmt(tmp->next->next, NULL, + BLOGC_TEMPLATE_ENDIF_STMT); + assert_null(tmp->next->next->next); blogc_template_free_stmts(stmts); } @@ -407,6 +425,22 @@ test_template_parse_invalid_ifdef_variable(void **state) static void +test_template_parse_invalid_if_operator(void **state) +{ + const char *a = "{% block entry %}{% if BOLA = \"asd\" %}\n"; + blogc_error_t *err = NULL; + b_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, + "Invalid 'if' operator. Must be '<', '>', '<=', '>=', '==' or '!='.\n" + "Error occurred near to '= \"asd\" %}'"); + blogc_error_free(err); +} + + +static void test_template_parse_invalid_block_end(void **state) { const char *a = "{% block entry }}\n"; @@ -505,7 +539,7 @@ test_template_parse_invalid_close2(void **state) static void test_template_parse_invalid_if_not_closed(void **state) { - const char *a = "{% block entry %}{% if BOLA %}{% endblock %}\n"; + const char *a = "{% block entry %}{% ifdef BOLA %}{% endblock %}\n"; blogc_error_t *err = NULL; b_slist_t *stmts = blogc_template_parse(a, strlen(a), &err); assert_non_null(err); @@ -547,6 +581,7 @@ main(void) unit_test(test_template_parse_invalid_block_type), unit_test(test_template_parse_invalid_ifdef_start), unit_test(test_template_parse_invalid_ifdef_variable), + unit_test(test_template_parse_invalid_if_operator), unit_test(test_template_parse_invalid_block_end), unit_test(test_template_parse_invalid_variable_name), unit_test(test_template_parse_invalid_variable_name2), |