aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael G. Martins <rafael@rafaelmartins.eng.br>2015-04-23 19:44:39 -0300
committerRafael G. Martins <rafael@rafaelmartins.eng.br>2015-04-23 19:44:39 -0300
commit7582a32c837c8b55613b547799d1a6405e926cba (patch)
tree91d1c6cd950b685ac29ab7b555b73ee7da2a04dd
parentc7241b7dba557674ae84f53bcf55cd8597be3559 (diff)
downloadblogc-7582a32c837c8b55613b547799d1a6405e926cba.tar.gz
blogc-7582a32c837c8b55613b547799d1a6405e926cba.tar.bz2
blogc-7582a32c837c8b55613b547799d1a6405e926cba.zip
template parser: added "if not" support
-rw-r--r--README.md2
-rw-r--r--src/renderer.c14
-rw-r--r--src/template-parser.c34
-rw-r--r--src/template-parser.h1
-rw-r--r--tests/check_renderer.c34
-rw-r--r--tests/check_template_parser.c21
6 files changed, 94 insertions, 12 deletions
diff --git a/README.md b/README.md
index d4d5287..c712c78 100644
--- a/README.md
+++ b/README.md
@@ -24,7 +24,7 @@ The templates can define blocks. These are the block rules:
The variables defined in the source file are only available inside of blocks. If something does not depends on the source files, and is global, it must be hardcoded in the template, for the sake of simplicity.
-The templates can use conditional statements: ``{% if variable %}`` and ``{% endif %}``. They check if a variable is defined or not. As variables are not available outside of blocks, these conditional statements can't be defined outside of blocks as well.
+The templates can use conditional statements: ``{% if VARIABLE %}`` or ``{% if not VARIABLE %}``, and ``{% endif %}``. They check if a variable is defined or not. As variables are not available outside of blocks, these conditional statements can't be defined outside of blocks as well.
Variables are not available in ``listing_once`` blocks, because it is not possible to guess which source file would provide the variable contents.
diff --git a/src/renderer.c b/src/renderer.c
index 69206c3..92fa7d4 100644
--- a/src/renderer.c
+++ b/src/renderer.c
@@ -34,6 +34,8 @@ blogc_render(b_slist_t *tmpl, b_slist_t *sources, bool listing)
unsigned int if_count = 0;
unsigned int if_skip = 0;
+ bool if_not = false;
+
b_slist_t *tmp = tmpl;
while (tmp != NULL) {
blogc_template_stmt_t *stmt = tmp->data;
@@ -104,9 +106,14 @@ blogc_render(b_slist_t *tmpl, b_slist_t *sources, bool listing)
}
break;
+ case BLOGC_TEMPLATE_IF_NOT_STMT:
+ if_not = true;
+
case BLOGC_TEMPLATE_IF_STMT:
if (stmt->value != NULL && tmp_source != NULL) {
- if (b_trie_lookup(tmp_source, stmt->value) == NULL) {
+ if ((!if_not && (b_trie_lookup(tmp_source, stmt->value) == NULL)) ||
+ (if_not && (b_trie_lookup(tmp_source, stmt->value) != NULL)))
+ {
if_skip = if_count;
// at this point we can just skip anything, counting the
@@ -115,7 +122,9 @@ blogc_render(b_slist_t *tmpl, b_slist_t *sources, bool listing)
while (1) {
tmp = tmp->next;
stmt = tmp->data;
- if (stmt->type == BLOGC_TEMPLATE_IF_STMT) {
+ if ((stmt->type == BLOGC_TEMPLATE_IF_STMT) ||
+ (stmt->type == BLOGC_TEMPLATE_IF_NOT_STMT))
+ {
if_count++;
continue;
}
@@ -129,6 +138,7 @@ blogc_render(b_slist_t *tmpl, b_slist_t *sources, bool listing)
}
}
}
+ if_not = false;
}
break;
diff --git a/src/template-parser.c b/src/template-parser.c
index 319ae4b..0fcf898 100644
--- a/src/template-parser.c
+++ b/src/template-parser.c
@@ -25,7 +25,8 @@ typedef enum {
TEMPLATE_BLOCK_TYPE,
TEMPLATE_BLOCK_BLOCK_TYPE_START,
TEMPLATE_BLOCK_BLOCK_TYPE,
- TEMPLATE_BLOCK_IF_VARIABLE_START,
+ TEMPLATE_BLOCK_IF_START,
+ TEMPLATE_BLOCK_IF_CONDITION,
TEMPLATE_BLOCK_IF_VARIABLE,
TEMPLATE_BLOCK_END,
TEMPLATE_VARIABLE_START,
@@ -54,6 +55,7 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
size_t end = 0;
unsigned int if_count = 0;
+ bool conditional = false;
b_slist_t *stmts = NULL;
blogc_template_stmt_t *stmt = NULL;
@@ -142,7 +144,7 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
}
else if (0 == strncmp("if", src + start, current - start)) {
if (block_state == BLOCK_ENTRY || block_state == BLOCK_LISTING) {
- state = TEMPLATE_BLOCK_IF_VARIABLE_START;
+ state = TEMPLATE_BLOCK_IF_START;
type = BLOGC_TEMPLATE_IF_STMT;
start = current;
if_count++;
@@ -222,9 +224,17 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
"and 'listing_once'.");
break;
- case TEMPLATE_BLOCK_IF_VARIABLE_START:
+ case TEMPLATE_BLOCK_IF_START:
if (c == ' ')
break;
+ if (c >= 'a' && c <= 'z') {
+ if (!conditional) {
+ conditional = true;
+ state = TEMPLATE_BLOCK_IF_CONDITION;
+ start = current;
+ break;
+ }
+ }
if (c >= 'A' && c <= 'Z') {
state = TEMPLATE_BLOCK_IF_VARIABLE;
start = current;
@@ -235,6 +245,23 @@ 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_IF_CONDITION:
+ if (c >= 'a' && c <= 'z')
+ break;
+ if (c == ' ') {
+ if (0 == strncmp("not", src + start, current - start)) {
+ block_state = BLOCK_ENTRY;
+ end = current;
+ state = TEMPLATE_BLOCK_IF_START;
+ type = BLOGC_TEMPLATE_IF_NOT_STMT;
+ break;
+ }
+ }
+ *err = blogc_error_parser(BLOGC_ERROR_TEMPLATE_PARSER, src,
+ src_len, current,
+ "Invalid 'if' condition. Allowed conditions are: 'not'.");
+ break;
+
case TEMPLATE_BLOCK_IF_VARIABLE:
if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')
break;
@@ -253,6 +280,7 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
if (c == ' ')
break;
if (c == '%') {
+ conditional = false;
state = TEMPLATE_CLOSE_BRACKET;
break;
}
diff --git a/src/template-parser.h b/src/template-parser.h
index d95c87a..8fe3630 100644
--- a/src/template-parser.h
+++ b/src/template-parser.h
@@ -14,6 +14,7 @@
typedef enum {
BLOGC_TEMPLATE_IF_STMT = 1,
+ BLOGC_TEMPLATE_IF_NOT_STMT,
BLOGC_TEMPLATE_ENDIF_STMT,
BLOGC_TEMPLATE_BLOCK_STMT,
BLOGC_TEMPLATE_ENDBLOCK_STMT,
diff --git a/tests/check_renderer.c b/tests/check_renderer.c
index bbc2953..539d122 100644
--- a/tests/check_renderer.c
+++ b/tests/check_renderer.c
@@ -214,6 +214,39 @@ test_render_if3(void **state)
static void
+test_render_if_not(void **state)
+{
+ const char *str =
+ "{% block entry %}\n"
+ "{% if not CHUNDA %}chunda\n"
+ "{% if GUDA %}guda\n"
+ "{% if not BOLA %}bola\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ b_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ b_slist_t *s = create_sources(1);
+ assert_non_null(s);
+ char *out = blogc_render(l, s, false);
+ assert_string_equal(out,
+ "\n"
+ "chunda\n"
+ "guda\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n");
+ blogc_template_free_stmts(l);
+ b_slist_free_full(s, (b_free_func_t) b_trie_free);
+ free(out);
+}
+
+
+static void
test_render_null(void **state)
{
assert_null(blogc_render(NULL, NULL, false));
@@ -229,6 +262,7 @@ main(void)
unit_test(test_render_if),
unit_test(test_render_if2),
unit_test(test_render_if3),
+ unit_test(test_render_if_not),
unit_test(test_render_null),
};
return run_tests(tests);
diff --git a/tests/check_template_parser.c b/tests/check_template_parser.c
index f4c0825..fcf4ee8 100644
--- a/tests/check_template_parser.c
+++ b/tests/check_template_parser.c
@@ -43,6 +43,9 @@ test_template_parse(void **state)
"{% if CHUNDA %}\n"
"bola\n"
"{% endif %}\n"
+ "{% if not BOLA %}\n"
+ "bolao\n"
+ "{% endif %}\n"
"{% endblock %}\n"
"{% block listing %}{{ BOLA }}{% endblock %}\n"
"{% block listing_once %}asd{% endblock %}\n";
@@ -60,19 +63,25 @@ test_template_parse(void **state)
BLOGC_TEMPLATE_IF_STMT);
blogc_assert_template_stmt(stmts->next->next->next->next, "\nbola\n",
BLOGC_TEMPLATE_CONTENT_STMT);
- blogc_assert_template_stmt(stmts->next->next->next->next->next,
- NULL, BLOGC_TEMPLATE_ENDIF_STMT);
- blogc_assert_template_stmt(stmts->next->next->next->next->next->next,
- "\n", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(stmts->next->next->next->next->next, NULL,
+ BLOGC_TEMPLATE_ENDIF_STMT);
+ blogc_assert_template_stmt(stmts->next->next->next->next->next->next, "\n",
+ BLOGC_TEMPLATE_CONTENT_STMT);
b_slist_t *tmp = stmts->next->next->next->next->next->next->next;
+ blogc_assert_template_stmt(tmp, "BOLA", BLOGC_TEMPLATE_IF_NOT_STMT);
+ blogc_assert_template_stmt(tmp->next, "\nbolao\n", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next, NULL, BLOGC_TEMPLATE_ENDIF_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next, "\n",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ tmp = tmp->next->next->next->next;
blogc_assert_template_stmt(tmp, NULL, BLOGC_TEMPLATE_ENDBLOCK_STMT);
blogc_assert_template_stmt(tmp->next, "\n", BLOGC_TEMPLATE_CONTENT_STMT);
blogc_assert_template_stmt(tmp->next->next, "listing",
BLOGC_TEMPLATE_BLOCK_STMT);
blogc_assert_template_stmt(tmp->next->next->next, "BOLA",
BLOGC_TEMPLATE_VARIABLE_STMT);
- blogc_assert_template_stmt(tmp->next->next->next->next, NULL,
- BLOGC_TEMPLATE_ENDBLOCK_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next,
+ NULL, BLOGC_TEMPLATE_ENDBLOCK_STMT);
blogc_assert_template_stmt(tmp->next->next->next->next->next, "\n",
BLOGC_TEMPLATE_CONTENT_STMT);
blogc_assert_template_stmt(tmp->next->next->next->next->next->next,