aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/template-parser.c136
-rw-r--r--src/template-parser.h3
-rw-r--r--tests/check_renderer.c14
-rw-r--r--tests/check_template_parser.c41
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),