From 8d96c02e5118cf7bd656fde9100570a67115d19a Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Tue, 29 Dec 2015 00:12:51 +0100
Subject: man: renderer: template-parser: added foreach iterator support
---
man/blogc-template.7.ronn | 38 +++++++++++++
src/renderer.c | 71 +++++++++++++++++++++++++
src/renderer.h | 2 +
src/template-parser.c | 67 ++++++++++++++++++++++-
src/template-parser.h | 2 +
tests/check_renderer.c | 70 +++++++++++++++++++++++-
tests/check_template_parser.c | 121 +++++++++++++++++++++++++++++++++++++++---
7 files changed, 361 insertions(+), 10 deletions(-)
diff --git a/man/blogc-template.7.ronn b/man/blogc-template.7.ronn
index 77073af..46413c2 100644
--- a/man/blogc-template.7.ronn
+++ b/man/blogc-template.7.ronn
@@ -163,6 +163,44 @@ Or:
Title is the default title
{% endif %}
+## TEMPLATE ITERATORS
+
+Template iterators are used to iterate over the value of a variable, that is handled
+as a list.
+
+The available conditionals are: `foreach`.
+
+### foreach iterator
+
+The content of a `foreach` iterator is included in the output file when the target
+variable is defined, and is repeated for each item in the list parsed from the variable
+value.
+
+The variable value should be formatted as a comma-separated list of items. Quotes are
+not supported, as this is intended to work with identifiers, like slugs, and not with
+arbitrary strings.
+
+Spaces and tabs before and after list items are stripped for consistency.
+
+This is how a variable would be formatted:
+
+ item1, item2, item3
+
+For more info about how to define variables, see blogc(1) and blogc-source(7).
+
+This is how a `foreach` iterator is defined in a template:
+
+ {% foreach TAGS %}
+ {{ FOREACH_ITEM }}
+ {% endforeach %}
+
+Where `TAGS` is the variable with comma-separated list of items, and `FOREACH_ITEM`
+is the variable defined by blogc(1), that will store the item value for a given
+iteration.
+
+If the value of the `TAGS` variable is "item1, item2, item3", this template would be
+rendered as 3 times, one for each item value.
+
## BUGS
The template content is handled by handwritten parsers, that even being well
diff --git a/src/renderer.c b/src/renderer.c
index 3061c43..6cf924e 100644
--- a/src/renderer.c
+++ b/src/renderer.c
@@ -88,6 +88,24 @@ blogc_format_variable(const char *name, b_trie_t *global, b_trie_t *local)
}
+b_slist_t*
+blogc_split_list_variable(const char *name, b_trie_t *global, b_trie_t *local)
+{
+ const char *value = blogc_get_variable(name, global, local);
+ if (value == NULL)
+ return NULL;
+
+ b_slist_t *rv = NULL;
+
+ char **tmp = b_str_split(value, ',', 0);
+ for (unsigned int i = 0; tmp[i] != NULL; i++)
+ rv = b_slist_append(rv, b_strdup(b_str_strip(tmp[i])));
+ b_strv_free(tmp);
+
+ return rv;
+}
+
+
char*
blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config, bool listing)
{
@@ -106,6 +124,10 @@ blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config, bool listing
unsigned int if_count = 0;
unsigned int if_skip = 0;
+ b_slist_t *foreach_var = NULL;
+ b_slist_t *foreach_var_start = NULL;
+ b_slist_t *foreach_start = NULL;
+
bool if_not = false;
bool inside_block = false;
bool evaluate = false;
@@ -174,6 +196,11 @@ blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config, bool listing
case BLOGC_TEMPLATE_VARIABLE_STMT:
if (stmt->value != NULL) {
+ if (0 == strcmp(stmt->value, "FOREACH_ITEM")) { // foreach
+ if (foreach_var != NULL && foreach_var->data != NULL)
+ b_string_append(str, foreach_var->data);
+ break;
+ }
config_value = blogc_format_variable(stmt->value,
config, inside_block ? tmp_source : NULL);
if (config_value != NULL) {
@@ -281,9 +308,53 @@ blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config, bool listing
case BLOGC_TEMPLATE_ENDIF_STMT:
if_count--;
break;
+
+ case BLOGC_TEMPLATE_FOREACH_STMT:
+ if (foreach_var_start == NULL) {
+ if (stmt->value != NULL)
+ foreach_var_start = blogc_split_list_variable(stmt->value,
+ config, inside_block ? tmp_source : NULL);
+
+ if (foreach_var_start != NULL) {
+ foreach_var = foreach_var_start;
+ foreach_start = tmp;
+ }
+ else {
+
+ // we can just skip anything and walk until the next
+ // 'endforeach'
+ while (stmt->type != BLOGC_TEMPLATE_ENDFOREACH_STMT) {
+ tmp = tmp->next;
+ stmt = tmp->data;
+ }
+ break;
+ }
+ }
+
+ if (foreach_var == NULL) {
+ foreach_start = tmp;
+ foreach_var = foreach_var_start;
+ }
+ break;
+
+ case BLOGC_TEMPLATE_ENDFOREACH_STMT:
+ if (foreach_start != NULL && foreach_var != NULL) {
+ foreach_var = foreach_var->next;
+ if (foreach_var != NULL) {
+ tmp = foreach_start;
+ continue;
+ }
+ }
+ foreach_start = NULL;
+ b_slist_free_full(foreach_var_start, free);
+ foreach_var_start = NULL;
+ break;
}
tmp = tmp->next;
}
+ // no need to free temporary variables here. the template parser makes sure
+ // that templates are sane and statements are closed.
+
return b_string_free(str, false);
}
diff --git a/src/renderer.h b/src/renderer.h
index e5cff6e..de26e98 100644
--- a/src/renderer.h
+++ b/src/renderer.h
@@ -15,6 +15,8 @@
const char* blogc_get_variable(const char *name, b_trie_t *global, b_trie_t *local);
char* blogc_format_date(const char *date, b_trie_t *global, b_trie_t *local);
char* blogc_format_variable(const char *name, b_trie_t *global, b_trie_t *local);
+b_slist_t* blogc_split_list_variable(const char *name, b_trie_t *global,
+ b_trie_t *local);
char* blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config,
bool listing);
diff --git a/src/template-parser.c b/src/template-parser.c
index f6912df..e5c750e 100644
--- a/src/template-parser.c
+++ b/src/template-parser.c
@@ -32,6 +32,8 @@ typedef enum {
TEMPLATE_BLOCK_IF_OPERAND_START,
TEMPLATE_BLOCK_IF_STRING_OPERAND,
TEMPLATE_BLOCK_IF_VARIABLE_OPERAND,
+ TEMPLATE_BLOCK_FOREACH_START,
+ TEMPLATE_BLOCK_FOREACH_VARIABLE,
TEMPLATE_BLOCK_END,
TEMPLATE_VARIABLE_START,
TEMPLATE_VARIABLE,
@@ -65,6 +67,7 @@ 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;
+ bool foreach_open = false;
b_slist_t *stmts = NULL;
blogc_template_stmt_t *stmt = NULL;
@@ -201,11 +204,42 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
"statement.");
break;
}
+ else if ((current - start == 7) &&
+ (0 == strncmp("foreach", src + start, 7)))
+ {
+ if (!foreach_open) {
+ state = TEMPLATE_BLOCK_FOREACH_START;
+ type = BLOGC_TEMPLATE_FOREACH_STMT;
+ start = current;
+ foreach_open = true;
+ break;
+ }
+ *err = blogc_error_parser(BLOGC_ERROR_TEMPLATE_PARSER,
+ src, src_len, current, "'foreach' statements can't "
+ "be nested.");
+ break;
+ }
+ else if ((current - start == 10) &&
+ (0 == strncmp("endforeach", src + start, 10)))
+ {
+ if (foreach_open) {
+ state = TEMPLATE_BLOCK_END;
+ type = BLOGC_TEMPLATE_ENDFOREACH_STMT;
+ foreach_open = false;
+ break;
+ }
+ *err = blogc_error_parser(BLOGC_ERROR_TEMPLATE_PARSER,
+ src, src_len, current,
+ "'endforeach' statement without an open 'foreach' "
+ "statement.");
+ break;
+ }
}
*err = blogc_error_parser(BLOGC_ERROR_TEMPLATE_PARSER, src,
src_len, current,
"Invalid statement type: Allowed types are: 'block', "
- "'endblock', 'ifdef', 'ifndef' and 'endif'.");
+ "'endblock', 'ifdef', 'ifndef', 'endif', 'foreach' and "
+ "'endforeach'.");
break;
case TEMPLATE_BLOCK_BLOCK_TYPE_START:
@@ -337,6 +371,34 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
end2 = current;
break;
+ case TEMPLATE_BLOCK_FOREACH_START:
+ if (c == ' ')
+ break;
+ if (c >= 'A' && c <= 'Z') {
+ state = TEMPLATE_BLOCK_FOREACH_VARIABLE;
+ start = current;
+ break;
+ }
+ *err = blogc_error_parser(BLOGC_ERROR_TEMPLATE_PARSER, src,
+ src_len, current,
+ "Invalid foreach variable name. Must begin with uppercase "
+ "letter.");
+ break;
+
+ case TEMPLATE_BLOCK_FOREACH_VARIABLE:
+ if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')
+ break;
+ if (c == ' ') {
+ end = current;
+ state = TEMPLATE_BLOCK_END;
+ break;
+ }
+ *err = blogc_error_parser(BLOGC_ERROR_TEMPLATE_PARSER, src,
+ src_len, current,
+ "Invalid foreach variable name. Must be uppercase letter, "
+ "number or '_'.");
+ break;
+
case TEMPLATE_BLOCK_END:
if (c == ' ')
break;
@@ -469,6 +531,9 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
else if (block_state != BLOCK_CLOSED)
*err = blogc_error_new(BLOGC_ERROR_TEMPLATE_PARSER,
"An open block was not closed!");
+ else if (foreach_open)
+ *err = blogc_error_new(BLOGC_ERROR_TEMPLATE_PARSER,
+ "An open 'foreach' statement was not closed!");
}
if (*err != NULL) {
diff --git a/src/template-parser.h b/src/template-parser.h
index d1e9bd6..9da5fff 100644
--- a/src/template-parser.h
+++ b/src/template-parser.h
@@ -17,6 +17,8 @@ typedef enum {
BLOGC_TEMPLATE_IFNDEF_STMT,
BLOGC_TEMPLATE_IF_STMT,
BLOGC_TEMPLATE_ENDIF_STMT,
+ BLOGC_TEMPLATE_FOREACH_STMT,
+ BLOGC_TEMPLATE_ENDFOREACH_STMT,
BLOGC_TEMPLATE_BLOCK_STMT,
BLOGC_TEMPLATE_ENDBLOCK_STMT,
BLOGC_TEMPLATE_VARIABLE_STMT,
diff --git a/tests/check_renderer.c b/tests/check_renderer.c
index cb8f8f1..cc04fdc 100644
--- a/tests/check_renderer.c
+++ b/tests/check_renderer.c
@@ -31,6 +31,7 @@ create_sources(unsigned int count)
"GUDA2: zxc\n"
"DATE: 2015-01-02 03:04:05\n"
"DATE_FORMAT: %R\n"
+ "TAGS: foo, bar,baz\n"
"-----\n"
"ahahahahahahahaha",
"BOLA: asd2\n"
@@ -74,7 +75,8 @@ test_render_entry(void **state)
"{% if GUDA != \"bola\" %}HEHE{% endif %}\n"
"{% if GUDA < \"zxd\" %}LOL2{% endif %}\n"
"{% if GUDA > \"zxd\" %}LOL3{% endif %}\n"
- "{% if GUDA <= \"zxc\" %}LOL4{% endif %}\n";
+ "{% if GUDA <= \"zxc\" %}LOL4{% endif %}\n"
+ "{% foreach TAGS %}lol {{ FOREACH_ITEM }} haha {% endforeach %}\n";
blogc_error_t *err = NULL;
b_slist_t *l = blogc_template_parse(str, strlen(str), &err);
assert_non_null(l);
@@ -97,7 +99,8 @@ test_render_entry(void **state)
"HEHE\n"
"LOL2\n"
"\n"
- "LOL4\n");
+ "LOL4\n"
+ "lol foo haha lol bar haha lol baz haha \n");
blogc_template_free_stmts(l);
b_slist_free_full(s, (b_free_func_t) b_trie_free);
free(out);
@@ -117,6 +120,7 @@ test_render_listing(void **state)
"{% block listing %}\n"
"{% ifdef DATE_FORMATTED %}{{ DATE_FORMATTED }}{% endif %}\n"
"bola: {% ifdef BOLA %}{{ BOLA }}{% endif %}\n"
+ "{% foreach TAGS %}lol {{ FOREACH_ITEM }} haha {% endforeach %}\n"
"{% endblock %}\n";
blogc_error_t *err = NULL;
b_slist_t *l = blogc_template_parse(str, strlen(str), &err);
@@ -132,12 +136,15 @@ test_render_listing(void **state)
"\n"
"03:04\n"
"bola: asd\n"
+ "lol foo haha lol bar haha lol baz haha \n"
"\n"
"2014-02-03 04:05:06\n"
"bola: asd2\n"
"\n"
+ "\n"
"2013-01-02 03:04:05\n"
"bola: asd3\n"
+ "\n"
"\n");
blogc_template_free_stmts(l);
b_slist_free_full(s, (b_free_func_t) b_trie_free);
@@ -158,6 +165,7 @@ test_render_listing_empty(void **state)
"{% block listing %}\n"
"{% ifdef DATE_FORMATTED %}{{ DATE_FORMATTED }}{% endif %}\n"
"bola: {% ifdef BOLA %}{{ BOLA }}{% endif %}\n"
+ "{% foreach TAGS %}lol {{ FOREACH_ITEM }} haha {% endforeach %}\n"
"{% endblock %}\n";
blogc_error_t *err = NULL;
b_slist_t *l = blogc_template_parse(str, strlen(str), &err);
@@ -518,6 +526,30 @@ test_render_if_gt_eq(void **state)
}
+static void
+test_render_foreach(void **state)
+{
+ const char *str =
+ "{% block entry %}\n"
+ "{% foreach TAGS %} {{ FOREACH_ITEM }} {% endforeach %}\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, NULL, false);
+ assert_string_equal(out,
+ "\n"
+ " foo bar baz \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)
{
@@ -760,6 +792,37 @@ test_format_variable_with_date(void **state)
}
+static void
+test_split_list_variable(void **state)
+{
+ b_trie_t *g = b_trie_new(free);
+ b_trie_insert(g, "TAGS", b_strdup("asd, lol,hehe"));
+ b_trie_t *l = b_trie_new(free);
+ b_trie_insert(l, "TAGS", b_strdup("asd, lol,XD"));
+ b_slist_t *tmp = blogc_split_list_variable("TAGS", g, l);
+ assert_string_equal(tmp->data, "asd");
+ assert_string_equal(tmp->next->data, "lol");
+ assert_string_equal(tmp->next->next->data, "XD");
+ b_slist_free_full(tmp, free);
+ b_trie_free(g);
+ b_trie_free(l);
+}
+
+
+static void
+test_split_list_variable_not_found(void **state)
+{
+ b_trie_t *g = b_trie_new(free);
+ b_trie_insert(g, "TAGS", b_strdup("asd, lol,hehe"));
+ b_trie_t *l = b_trie_new(free);
+ b_trie_insert(l, "TAGS", b_strdup("asd, lol,XD"));
+ b_slist_t *tmp = blogc_split_list_variable("TAG", g, l);
+ assert_null(tmp);
+ b_trie_free(g);
+ b_trie_free(l);
+}
+
+
int
main(void)
{
@@ -777,6 +840,7 @@ main(void)
unit_test(test_render_if_gt),
unit_test(test_render_if_lt_eq),
unit_test(test_render_if_gt_eq),
+ unit_test(test_render_foreach),
unit_test(test_render_null),
unit_test(test_render_outside_block),
unit_test(test_render_prefer_local_variable),
@@ -790,6 +854,8 @@ main(void)
unit_test(test_format_date_without_date),
unit_test(test_format_variable),
unit_test(test_format_variable_with_date),
+ unit_test(test_split_list_variable),
+ unit_test(test_split_list_variable_not_found),
};
return run_tests(tests);
}
diff --git a/tests/check_template_parser.c b/tests/check_template_parser.c
index b712f22..6aaceed 100644
--- a/tests/check_template_parser.c
+++ b/tests/check_template_parser.c
@@ -61,6 +61,7 @@ test_template_parse(void **state)
"{% endblock %}\n"
"{% block listing %}{{ BOLA }}{% endblock %}\n"
"{% block listing_once %}asd{% endblock %}\n"
+ "{% foreach BOLA %}hahaha{% endforeach %}\n"
"{% if BOLA == \"1\\\"0\" %}aee{% endif %}";
blogc_error_t *err = NULL;
b_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
@@ -106,11 +107,20 @@ test_template_parse(void **state)
blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next->next->next,
"\n", BLOGC_TEMPLATE_CONTENT_STMT);
tmp = tmp->next->next->next->next->next->next->next->next->next->next;
- blogc_assert_template_if_stmt(tmp, "BOLA", BLOGC_TEMPLATE_OP_EQ, "\"1\\\"0\"");
- blogc_assert_template_stmt(tmp->next, "aee", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp, "BOLA", BLOGC_TEMPLATE_FOREACH_STMT);
+ blogc_assert_template_stmt(tmp->next, "hahaha",
+ BLOGC_TEMPLATE_CONTENT_STMT);
blogc_assert_template_stmt(tmp->next->next, NULL,
+ BLOGC_TEMPLATE_ENDFOREACH_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next, "\n",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_if_stmt(tmp->next->next->next->next, "BOLA",
+ BLOGC_TEMPLATE_OP_EQ, "\"1\\\"0\"");
+ blogc_assert_template_stmt(tmp->next->next->next->next->next, "aee",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next, NULL,
BLOGC_TEMPLATE_ENDIF_STMT);
- assert_null(tmp->next->next->next);
+ assert_null(tmp->next->next->next->next->next->next->next);
blogc_template_free_stmts(stmts);
}
@@ -131,6 +141,7 @@ test_template_parse_crlf(void **state)
"{% endblock %}\r\n"
"{% block listing %}{{ BOLA }}{% endblock %}\r\n"
"{% block listing_once %}asd{% endblock %}\r\n"
+ "{% foreach BOLA %}hahaha{% endforeach %}\r\n"
"{% if BOLA == \"1\\\"0\" %}aee{% endif %}";
blogc_error_t *err = NULL;
b_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
@@ -176,11 +187,20 @@ test_template_parse_crlf(void **state)
blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next->next->next,
"\r\n", BLOGC_TEMPLATE_CONTENT_STMT);
tmp = tmp->next->next->next->next->next->next->next->next->next->next;
- blogc_assert_template_if_stmt(tmp, "BOLA", BLOGC_TEMPLATE_OP_EQ, "\"1\\\"0\"");
- blogc_assert_template_stmt(tmp->next, "aee", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp, "BOLA", BLOGC_TEMPLATE_FOREACH_STMT);
+ blogc_assert_template_stmt(tmp->next, "hahaha",
+ BLOGC_TEMPLATE_CONTENT_STMT);
blogc_assert_template_stmt(tmp->next->next, NULL,
+ BLOGC_TEMPLATE_ENDFOREACH_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next, "\r\n",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_if_stmt(tmp->next->next->next->next, "BOLA",
+ BLOGC_TEMPLATE_OP_EQ, "\"1\\\"0\"");
+ blogc_assert_template_stmt(tmp->next->next->next->next->next, "aee",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next, NULL,
BLOGC_TEMPLATE_ENDIF_STMT);
- assert_null(tmp->next->next->next);
+ assert_null(tmp->next->next->next->next->next->next->next);
blogc_template_free_stmts(stmts);
}
@@ -382,6 +402,24 @@ test_template_parse_invalid_block_nested(void **state)
}
+static void
+test_template_parse_invalid_foreach_nested(void **state)
+{
+ const char *a =
+ "{% foreach A %}\n"
+ "{% foreach B %}\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,
+ "'foreach' statements can't be nested.\n"
+ "Error occurred near line 2, position 11: {% foreach B %}");
+ blogc_error_free(err);
+}
+
+
static void
test_template_parse_invalid_block_not_open(void **state)
{
@@ -415,6 +453,22 @@ test_template_parse_invalid_endif_not_open(void **state)
}
+static void
+test_template_parse_invalid_endforeach_not_open(void **state)
+{
+ const char *a = "{% endforeach %}\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,
+ "'endforeach' statement without an open 'foreach' statement.\n"
+ "Error occurred near line 1, position 14: {% endforeach %}");
+ blogc_error_free(err);
+}
+
+
static void
test_template_parse_invalid_block_name(void **state)
{
@@ -426,7 +480,7 @@ test_template_parse_invalid_block_name(void **state)
assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
assert_string_equal(err->msg,
"Invalid statement type: Allowed types are: 'block', 'endblock', 'ifdef', "
- "'ifndef' and 'endif'.\n"
+ "'ifndef', 'endif', 'foreach' and 'endforeach'.\n"
"Error occurred near line 1, position 10: {% chunda %}");
blogc_error_free(err);
}
@@ -481,6 +535,23 @@ test_template_parse_invalid_ifdef_start(void **state)
}
+static void
+test_template_parse_invalid_foreach_start(void **state)
+{
+ const char *a = "{% block entry %}{% foreach guda %}\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 foreach variable name. Must begin with uppercase letter.\n"
+ "Error occurred near line 1, position 29: "
+ "{% block entry %}{% foreach guda %}");
+ blogc_error_free(err);
+}
+
+
static void
test_template_parse_invalid_ifdef_variable(void **state)
{
@@ -498,6 +569,23 @@ test_template_parse_invalid_ifdef_variable(void **state)
}
+static void
+test_template_parse_invalid_foreach_variable(void **state)
+{
+ const char *a = "{% block entry %}{% foreach BoLA %}\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 foreach variable name. Must be uppercase letter, number or '_'.\n"
+ "Error occurred near line 1, position 30: "
+ "{% block entry %}{% foreach BoLA %}");
+ blogc_error_free(err);
+}
+
+
static void
test_template_parse_invalid_if_operator(void **state)
{
@@ -678,6 +766,20 @@ test_template_parse_invalid_block_not_closed(void **state)
}
+static void
+test_template_parse_invalid_foreach_not_closed(void **state)
+{
+ const char *a = "{% foreach 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, "An open 'foreach' statement was not closed!");
+ blogc_error_free(err);
+}
+
+
int
main(void)
{
@@ -688,13 +790,17 @@ main(void)
unit_test(test_template_parse_ifdef_and_var_outside_block),
unit_test(test_template_parse_invalid_block_start),
unit_test(test_template_parse_invalid_block_nested),
+ 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_endforeach_not_open),
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),
unit_test(test_template_parse_invalid_ifdef_start),
+ unit_test(test_template_parse_invalid_foreach_start),
unit_test(test_template_parse_invalid_ifdef_variable),
+ unit_test(test_template_parse_invalid_foreach_variable),
unit_test(test_template_parse_invalid_if_operator),
unit_test(test_template_parse_invalid_if_operand),
unit_test(test_template_parse_invalid_if_operand2),
@@ -706,6 +812,7 @@ main(void)
unit_test(test_template_parse_invalid_close2),
unit_test(test_template_parse_invalid_if_not_closed),
unit_test(test_template_parse_invalid_block_not_closed),
+ unit_test(test_template_parse_invalid_foreach_not_closed),
};
return run_tests(tests);
}
--
cgit v1.2.3-18-g5258
From e727bdcde63804a308103adeaa2637c5ee1ebdc8 Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Tue, 29 Dec 2015 00:39:01 +0100
Subject: template-parser: do not accept variables startins with numbers and _
---
src/template-parser.c | 19 +++++------
tests/check_template_parser.c | 74 ++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 83 insertions(+), 10 deletions(-)
diff --git a/src/template-parser.c b/src/template-parser.c
index e5c750e..030ecca 100644
--- a/src/template-parser.c
+++ b/src/template-parser.c
@@ -338,21 +338,22 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
case TEMPLATE_BLOCK_IF_OPERAND_START:
if (c == ' ')
break;
- if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_') {
+ if (c >= 'A' && c <= 'Z') {
state = TEMPLATE_BLOCK_IF_VARIABLE_OPERAND;
start2 = current;
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.");
+ if (c == '"') {
+ state = TEMPLATE_BLOCK_IF_STRING_OPERAND;
+ start2 = current;
break;
}
- state = TEMPLATE_BLOCK_IF_STRING_OPERAND;
- start2 = current;
+ 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 or variable.");
break;
case TEMPLATE_BLOCK_IF_STRING_OPERAND:
diff --git a/tests/check_template_parser.c b/tests/check_template_parser.c
index 6aaceed..145a27e 100644
--- a/tests/check_template_parser.c
+++ b/tests/check_template_parser.c
@@ -569,6 +569,23 @@ test_template_parse_invalid_ifdef_variable(void **state)
}
+static void
+test_template_parse_invalid_ifdef_variable2(void **state)
+{
+ const char *a = "{% block entry %}{% ifdef 0123 %}\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 variable name. Must begin with uppercase letter.\n"
+ "Error occurred near line 1, position 27: "
+ "{% block entry %}{% ifdef 0123 %}");
+ blogc_error_free(err);
+}
+
+
static void
test_template_parse_invalid_foreach_variable(void **state)
{
@@ -586,6 +603,23 @@ test_template_parse_invalid_foreach_variable(void **state)
}
+static void
+test_template_parse_invalid_foreach_variable2(void **state)
+{
+ const char *a = "{% block entry %}{% foreach 0123 %}\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 foreach variable name. Must begin with uppercase letter.\n"
+ "Error occurred near line 1, position 29: {% block entry %}"
+ "{% foreach 0123 %}");
+ blogc_error_free(err);
+}
+
+
static void
test_template_parse_invalid_if_operator(void **state)
{
@@ -613,7 +647,7 @@ test_template_parse_invalid_if_operand(void **state)
assert_null(stmts);
assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
assert_string_equal(err->msg,
- "Invalid 'if' operand. Must be double-quoted static string.\n"
+ "Invalid 'if' operand. Must be double-quoted static string or variable.\n"
"Error occurred near line 1, position 32: "
"{% block entry %}{% if BOLA == asd %}");
blogc_error_free(err);
@@ -637,6 +671,23 @@ test_template_parse_invalid_if_operand2(void **state)
}
+static void
+test_template_parse_invalid_if_operand3(void **state)
+{
+ const char *a = "{% block entry %}{% if BOLA == 0123 %}\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' operand. Must be double-quoted static string or variable.\n"
+ "Error occurred near line 1, position 32: "
+ "{% block entry %}{% if BOLA == 0123 %}");
+ blogc_error_free(err);
+}
+
+
static void
test_template_parse_invalid_block_end(void **state)
{
@@ -687,6 +738,23 @@ test_template_parse_invalid_variable_name2(void **state)
}
+static void
+test_template_parse_invalid_variable_name3(void **state)
+{
+ const char *a = "{% block entry %}{{ 0123 }}{% endblock %}\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 variable name. Must begin with uppercase letter.\n"
+ "Error occurred near line 1, position 21: {% block entry %}{{ 0123 }}"
+ "{% endblock %}");
+ blogc_error_free(err);
+}
+
+
static void
test_template_parse_invalid_variable_end(void **state)
{
@@ -800,13 +868,17 @@ main(void)
unit_test(test_template_parse_invalid_ifdef_start),
unit_test(test_template_parse_invalid_foreach_start),
unit_test(test_template_parse_invalid_ifdef_variable),
+ unit_test(test_template_parse_invalid_ifdef_variable2),
unit_test(test_template_parse_invalid_foreach_variable),
+ unit_test(test_template_parse_invalid_foreach_variable2),
unit_test(test_template_parse_invalid_if_operator),
unit_test(test_template_parse_invalid_if_operand),
unit_test(test_template_parse_invalid_if_operand2),
+ unit_test(test_template_parse_invalid_if_operand3),
unit_test(test_template_parse_invalid_block_end),
unit_test(test_template_parse_invalid_variable_name),
unit_test(test_template_parse_invalid_variable_name2),
+ unit_test(test_template_parse_invalid_variable_name3),
unit_test(test_template_parse_invalid_variable_end),
unit_test(test_template_parse_invalid_close),
unit_test(test_template_parse_invalid_close2),
--
cgit v1.2.3-18-g5258
From 3d24a8847e156804e19515ddeefd3912402515be Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Tue, 29 Dec 2015 01:46:50 +0100
Subject: renderer: foreach variables should be splitted in spaces rather than
commas
---
man/blogc-template.7.ronn | 14 ++++++--------
src/renderer.c | 12 ++++++++----
tests/check_renderer.c | 10 +++++-----
3 files changed, 19 insertions(+), 17 deletions(-)
diff --git a/man/blogc-template.7.ronn b/man/blogc-template.7.ronn
index 46413c2..2875e36 100644
--- a/man/blogc-template.7.ronn
+++ b/man/blogc-template.7.ronn
@@ -176,15 +176,13 @@ The content of a `foreach` iterator is included in the output file when the targ
variable is defined, and is repeated for each item in the list parsed from the variable
value.
-The variable value should be formatted as a comma-separated list of items. Quotes are
+The variable value should be formatted as a space-separated list of items. Quotes are
not supported, as this is intended to work with identifiers, like slugs, and not with
arbitrary strings.
-Spaces and tabs before and after list items are stripped for consistency.
+This is how a variable value would be formatted:
-This is how a variable would be formatted:
-
- item1, item2, item3
+ item1 item2 item3
For more info about how to define variables, see blogc(1) and blogc-source(7).
@@ -194,12 +192,12 @@ This is how a `foreach` iterator is defined in a template:
{{ FOREACH_ITEM }}
{% endforeach %}
-Where `TAGS` is the variable with comma-separated list of items, and `FOREACH_ITEM`
+Where `TAGS` is the variable with space-separated list of items, and `FOREACH_ITEM`
is the variable defined by blogc(1), that will store the item value for a given
iteration.
-If the value of the `TAGS` variable is "item1, item2, item3", this template would be
-rendered as 3 times, one for each item value.
+If the value of the `TAGS` variable is "item1 item2 item3", this template is
+rendered 3 times, one for each item value.
## BUGS
diff --git a/src/renderer.c b/src/renderer.c
index 6cf924e..defbe10 100644
--- a/src/renderer.c
+++ b/src/renderer.c
@@ -97,10 +97,14 @@ blogc_split_list_variable(const char *name, b_trie_t *global, b_trie_t *local)
b_slist_t *rv = NULL;
- char **tmp = b_str_split(value, ',', 0);
- for (unsigned int i = 0; tmp[i] != NULL; i++)
- rv = b_slist_append(rv, b_strdup(b_str_strip(tmp[i])));
- b_strv_free(tmp);
+ char **tmp = b_str_split(value, ' ', 0);
+ for (unsigned int i = 0; tmp[i] != NULL; i++) {
+ if (tmp[i][0] != '\0') // ignore empty strings
+ rv = b_slist_append(rv, tmp[i]);
+ else
+ free(tmp[i]);
+ }
+ free(tmp);
return rv;
}
diff --git a/tests/check_renderer.c b/tests/check_renderer.c
index cc04fdc..e380be7 100644
--- a/tests/check_renderer.c
+++ b/tests/check_renderer.c
@@ -31,7 +31,7 @@ create_sources(unsigned int count)
"GUDA2: zxc\n"
"DATE: 2015-01-02 03:04:05\n"
"DATE_FORMAT: %R\n"
- "TAGS: foo, bar,baz\n"
+ "TAGS: foo bar baz\n"
"-----\n"
"ahahahahahahahaha",
"BOLA: asd2\n"
@@ -796,9 +796,9 @@ static void
test_split_list_variable(void **state)
{
b_trie_t *g = b_trie_new(free);
- b_trie_insert(g, "TAGS", b_strdup("asd, lol,hehe"));
+ b_trie_insert(g, "TAGS", b_strdup("asd lol hehe"));
b_trie_t *l = b_trie_new(free);
- b_trie_insert(l, "TAGS", b_strdup("asd, lol,XD"));
+ b_trie_insert(l, "TAGS", b_strdup("asd lol XD"));
b_slist_t *tmp = blogc_split_list_variable("TAGS", g, l);
assert_string_equal(tmp->data, "asd");
assert_string_equal(tmp->next->data, "lol");
@@ -813,9 +813,9 @@ static void
test_split_list_variable_not_found(void **state)
{
b_trie_t *g = b_trie_new(free);
- b_trie_insert(g, "TAGS", b_strdup("asd, lol,hehe"));
+ b_trie_insert(g, "TAGS", b_strdup("asd lol hehe"));
b_trie_t *l = b_trie_new(free);
- b_trie_insert(l, "TAGS", b_strdup("asd, lol,XD"));
+ b_trie_insert(l, "TAGS", b_strdup("asd lol XD"));
b_slist_t *tmp = blogc_split_list_variable("TAG", g, l);
assert_null(tmp);
b_trie_free(g);
--
cgit v1.2.3-18-g5258
From 1b851a5778196a34affe397e4c502b326afd3270 Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Tue, 29 Dec 2015 22:32:38 +0100
Subject: loader: parse tags as space-separated string
---
src/loader.c | 9 ++++++---
tests/check_loader.c | 4 ++--
2 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/src/loader.c b/src/loader.c
index 8f04dae..5cd24df 100644
--- a/src/loader.c
+++ b/src/loader.c
@@ -141,11 +141,14 @@ blogc_source_parse_from_files(b_trie_t *conf, b_slist_t *l, blogc_error_t **err)
b_trie_free(s);
continue;
}
- char **tags = b_str_split(tags_str, ',', 0);
+ char **tags = b_str_split(tags_str, ' ', 0);
bool found = false;
- for (unsigned int i = 0; tags[i] != NULL; i++)
- if (0 == strcmp(b_str_strip(tags[i]), filter_tag))
+ for (unsigned int i = 0; tags[i] != NULL; i++) {
+ if (tags[i][0] == '\0')
+ continue;
+ if (0 == strcmp(tags[i], filter_tag))
found = true;
+ }
b_strv_free(tags);
if (!found) {
b_trie_free(s);
diff --git a/tests/check_loader.c b/tests/check_loader.c
index f5be3e7..03f0ef1 100644
--- a/tests/check_loader.c
+++ b/tests/check_loader.c
@@ -478,7 +478,7 @@ test_source_parse_from_files_filter_by_page_and_tag(void **state)
will_return(__wrap_blogc_file_get_contents, b_strdup(
"ASD: 789\n"
"DATE: 2003-02-03 04:05:06\n"
- "TAGS: chunda, bola\n"
+ "TAGS: chunda bola\n"
"--------\n"
"bola"));
will_return(__wrap_blogc_file_get_contents, "bola4.txt");
@@ -505,7 +505,7 @@ test_source_parse_from_files_filter_by_page_and_tag(void **state)
will_return(__wrap_blogc_file_get_contents, b_strdup(
"ASD: 7894\n"
"DATE: 2007-02-03 04:05:06\n"
- "TAGS: yay, chunda\n"
+ "TAGS: yay chunda\n"
"--------\n"
"bola"));
blogc_error_t *err = NULL;
--
cgit v1.2.3-18-g5258
From be71d0c966e558555ccdc25539e7f9be2ca1693b Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Wed, 30 Dec 2015 01:53:31 +0100
Subject: man: fix blogc-template man page
---
man/blogc-template.7.ronn | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/man/blogc-template.7.ronn b/man/blogc-template.7.ronn
index 2875e36..3a665ab 100644
--- a/man/blogc-template.7.ronn
+++ b/man/blogc-template.7.ronn
@@ -4,8 +4,8 @@ blogc-template(7) -- blogc's template format
## DESCRIPTION
Template files are used as base to build output files by blogc(1). These files
-can include variables, blocks and conditionals, that will directly affect the
-output files.
+can include variables, blocks, conditionals and iterators, that will directly
+affect the output files.
The syntax of the template files is defined to be simple, without affecting the
content output. The syntax is somewhat inspired by Jinja2 syntax.
--
cgit v1.2.3-18-g5258
From 02f4db9ceaff5ebd64122c958c4d6746191e9308 Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Fri, 1 Jan 2016 19:55:04 +0100
Subject: build: do not use AM_PROG_AR, as it is useless for us
---
configure.ac | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/configure.ac b/configure.ac
index 3cfb07d..43a336c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,15 +4,13 @@ AC_INIT([blogc], [0.5.1], [https://github.com/blogc/blogc], [blogc], [https://bl
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
-AM_INIT_AUTOMAKE([1.13 foreign dist-bzip2 dist-xz dist-zip subdir-objects serial-tests -Wall -Werror])
+AM_INIT_AUTOMAKE([1.13 foreign dist-bzip2 dist-xz dist-zip subdir-objects serial-tests -Wall -Wno-extra-portability -Werror])
AC_CONFIG_HEADERS([config.h])
AM_SILENT_RULES([yes])
AM_MAINTAINER_MODE([enable])
AC_USE_SYSTEM_EXTENSIONS
-AM_PROG_AR
-
LT_INIT
AC_PROG_CC_C99
--
cgit v1.2.3-18-g5258
From aa8b4d635405db2b8c46e42480789d1c1e14d8c4 Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Fri, 1 Jan 2016 19:57:28 +0100
Subject: build: minor style fixes
---
configure.ac | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac
index 43a336c..403bfec 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,10 +1,12 @@
AC_PREREQ([2.69])
-AC_INIT([blogc], [0.5.1], [https://github.com/blogc/blogc], [blogc], [https://blogc.rgm.io])
+AC_INIT([blogc], [0.5.1], [https://github.com/blogc/blogc], [blogc],
+ [https://blogc.rgm.io])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
-AM_INIT_AUTOMAKE([1.13 foreign dist-bzip2 dist-xz dist-zip subdir-objects serial-tests -Wall -Wno-extra-portability -Werror])
+AM_INIT_AUTOMAKE([1.13 foreign dist-bzip2 dist-xz dist-zip subdir-objects
+ serial-tests -Wall -Wno-extra-portability -Werror])
AC_CONFIG_HEADERS([config.h])
AM_SILENT_RULES([yes])
AM_MAINTAINER_MODE([enable])
--
cgit v1.2.3-18-g5258
From a5b155fde8c69d8954a13a4ff6fbdb7633094da7 Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Mon, 4 Jan 2016 00:33:06 +0100
Subject: renderer: improved foreach tests
---
tests/check_renderer.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/tests/check_renderer.c b/tests/check_renderer.c
index e380be7..d641506 100644
--- a/tests/check_renderer.c
+++ b/tests/check_renderer.c
@@ -76,7 +76,8 @@ test_render_entry(void **state)
"{% if GUDA < \"zxd\" %}LOL2{% endif %}\n"
"{% if GUDA > \"zxd\" %}LOL3{% endif %}\n"
"{% if GUDA <= \"zxc\" %}LOL4{% endif %}\n"
- "{% foreach TAGS %}lol {{ FOREACH_ITEM }} haha {% endforeach %}\n";
+ "{% foreach TAGS %}lol {{ FOREACH_ITEM }} haha {% endforeach %}\n"
+ "{% foreach TAGS_ASD %}yay{% endforeach %}\n";
blogc_error_t *err = NULL;
b_slist_t *l = blogc_template_parse(str, strlen(str), &err);
assert_non_null(l);
@@ -100,7 +101,8 @@ test_render_entry(void **state)
"LOL2\n"
"\n"
"LOL4\n"
- "lol foo haha lol bar haha lol baz haha \n");
+ "lol foo haha lol bar haha lol baz haha \n"
+ "\n");
blogc_template_free_stmts(l);
b_slist_free_full(s, (b_free_func_t) b_trie_free);
free(out);
@@ -121,6 +123,7 @@ test_render_listing(void **state)
"{% ifdef DATE_FORMATTED %}{{ DATE_FORMATTED }}{% endif %}\n"
"bola: {% ifdef BOLA %}{{ BOLA }}{% endif %}\n"
"{% foreach TAGS %}lol {{ FOREACH_ITEM }} haha {% endforeach %}\n"
+ "{% foreach TAGS_ASD %}yay{% endforeach %}\n"
"{% endblock %}\n";
blogc_error_t *err = NULL;
b_slist_t *l = blogc_template_parse(str, strlen(str), &err);
@@ -138,13 +141,16 @@ test_render_listing(void **state)
"bola: asd\n"
"lol foo haha lol bar haha lol baz haha \n"
"\n"
+ "\n"
"2014-02-03 04:05:06\n"
"bola: asd2\n"
"\n"
"\n"
+ "\n"
"2013-01-02 03:04:05\n"
"bola: asd3\n"
"\n"
+ "\n"
"\n");
blogc_template_free_stmts(l);
b_slist_free_full(s, (b_free_func_t) b_trie_free);
--
cgit v1.2.3-18-g5258
From fc0e0f4c2415b816daaca8d292aada532be19faa Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Thu, 7 Jan 2016 03:20:43 +0100
Subject: build: version bump
---
configure.ac | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/configure.ac b/configure.ac
index 403bfec..ffb61ac 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
AC_PREREQ([2.69])
-AC_INIT([blogc], [0.5.1], [https://github.com/blogc/blogc], [blogc],
+AC_INIT([blogc], [0.6], [https://github.com/blogc/blogc], [blogc],
[https://blogc.rgm.io])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
--
cgit v1.2.3-18-g5258
From 56a5ebf7f0b0d86b7d6e3fd468d3415da312e69b Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Fri, 8 Jan 2016 02:36:17 +0100
Subject: renderer: handle FOREACH_ITEM as a normal variable
---
src/renderer.c | 22 ++++++++++++--------
src/renderer.h | 3 ++-
tests/check_renderer.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++----
3 files changed, 67 insertions(+), 14 deletions(-)
diff --git a/src/renderer.c b/src/renderer.c
index defbe10..2fb60b5 100644
--- a/src/renderer.c
+++ b/src/renderer.c
@@ -58,8 +58,16 @@ blogc_format_date(const char *date, b_trie_t *global, b_trie_t *local)
char*
-blogc_format_variable(const char *name, b_trie_t *global, b_trie_t *local)
+blogc_format_variable(const char *name, b_trie_t *global, b_trie_t *local,
+ b_slist_t *foreach_var)
{
+ if (0 == strcmp(name, "FOREACH_ITEM")) {
+ if (foreach_var != NULL && foreach_var->data != NULL) {
+ return b_strdup(foreach_var->data);
+ }
+ return NULL;
+ }
+
char *var = NULL;
bool must_format = false;
if (b_str_ends_with(name, "_FORMATTED")) {
@@ -200,13 +208,8 @@ blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config, bool listing
case BLOGC_TEMPLATE_VARIABLE_STMT:
if (stmt->value != NULL) {
- if (0 == strcmp(stmt->value, "FOREACH_ITEM")) { // foreach
- if (foreach_var != NULL && foreach_var->data != NULL)
- b_string_append(str, foreach_var->data);
- break;
- }
config_value = blogc_format_variable(stmt->value,
- config, inside_block ? tmp_source : NULL);
+ config, inside_block ? tmp_source : NULL, foreach_var);
if (config_value != NULL) {
b_string_append(str, config_value);
free(config_value);
@@ -237,7 +240,7 @@ blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config, bool listing
defined = NULL;
if (stmt->value != NULL)
defined = blogc_format_variable(stmt->value, config,
- inside_block ? tmp_source : NULL);
+ inside_block ? tmp_source : NULL, foreach_var);
evaluate = false;
if (stmt->op != 0) {
// Strings that start with a '"' are actually strings, the
@@ -254,7 +257,8 @@ blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config, bool listing
}
else {
defined2 = blogc_format_variable(stmt->value2,
- config, inside_block ? tmp_source : NULL);
+ config, inside_block ? tmp_source : NULL,
+ foreach_var);
}
}
diff --git a/src/renderer.h b/src/renderer.h
index de26e98..d99fea0 100644
--- a/src/renderer.h
+++ b/src/renderer.h
@@ -14,7 +14,8 @@
const char* blogc_get_variable(const char *name, b_trie_t *global, b_trie_t *local);
char* blogc_format_date(const char *date, b_trie_t *global, b_trie_t *local);
-char* blogc_format_variable(const char *name, b_trie_t *global, b_trie_t *local);
+char* blogc_format_variable(const char *name, b_trie_t *global, b_trie_t *local,
+ b_slist_t *foreach_var);
b_slist_t* blogc_split_list_variable(const char *name, b_trie_t *global,
b_trie_t *local);
char* blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config,
diff --git a/tests/check_renderer.c b/tests/check_renderer.c
index d641506..014cd84 100644
--- a/tests/check_renderer.c
+++ b/tests/check_renderer.c
@@ -556,6 +556,31 @@ test_render_foreach(void **state)
}
+static void
+test_render_foreach_if(void **state)
+{
+ const char *str =
+ "{% block entry %}\n"
+ "{% foreach TAGS %} {% if FOREACH_ITEM == \"bar\" %}{{ FOREACH_ITEM }}"
+ "{% endif %} {% endforeach %}\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, NULL, false);
+ assert_string_equal(out,
+ "\n"
+ " bar \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)
{
@@ -770,13 +795,13 @@ test_format_variable(void **state)
b_trie_t *l = b_trie_new(free);
b_trie_insert(l, "NAME", b_strdup("chunda"));
b_trie_insert(l, "TITLE", b_strdup("chunda2"));
- char *tmp = blogc_format_variable("NAME", g, l);
+ char *tmp = blogc_format_variable("NAME", g, l, NULL);
assert_string_equal(tmp, "chunda");
free(tmp);
- tmp = blogc_format_variable("TITLE", g, l);
+ tmp = blogc_format_variable("TITLE", g, l, NULL);
assert_string_equal(tmp, "chunda2");
free(tmp);
- assert_null(blogc_format_variable("BOLA", g, l));
+ assert_null(blogc_format_variable("BOLA", g, l, NULL));
b_trie_free(g);
b_trie_free(l);
}
@@ -790,7 +815,7 @@ test_format_variable_with_date(void **state)
b_trie_insert(g, "DATE_FORMAT", b_strdup("%R"));
b_trie_t *l = b_trie_new(free);
b_trie_insert(l, "DATE", b_strdup("2011-12-13 14:15:16"));
- char *tmp = blogc_format_variable("DATE_FORMATTED", g, l);
+ char *tmp = blogc_format_variable("DATE_FORMATTED", g, l, NULL);
assert_string_equal(tmp, "14:15");
free(tmp);
b_trie_free(g);
@@ -798,6 +823,26 @@ test_format_variable_with_date(void **state)
}
+static void
+test_format_variable_foreach(void **state)
+{
+ b_slist_t *l = NULL;
+ l = b_slist_append(l, b_strdup("asd"));
+ l = b_slist_append(l, b_strdup("qwe"));
+ char *tmp = blogc_format_variable("FOREACH_ITEM", NULL, NULL, l->next);
+ assert_string_equal(tmp, "qwe");
+ free(tmp);
+ b_slist_free_full(l, free);
+}
+
+
+static void
+test_format_variable_foreach_empty(void **state)
+{
+ assert_null(blogc_format_variable("FOREACH_ITEM", NULL, NULL, NULL));
+}
+
+
static void
test_split_list_variable(void **state)
{
@@ -847,6 +892,7 @@ main(void)
unit_test(test_render_if_lt_eq),
unit_test(test_render_if_gt_eq),
unit_test(test_render_foreach),
+ unit_test(test_render_foreach_if),
unit_test(test_render_null),
unit_test(test_render_outside_block),
unit_test(test_render_prefer_local_variable),
@@ -860,6 +906,8 @@ main(void)
unit_test(test_format_date_without_date),
unit_test(test_format_variable),
unit_test(test_format_variable_with_date),
+ unit_test(test_format_variable_foreach),
+ unit_test(test_format_variable_foreach_empty),
unit_test(test_split_list_variable),
unit_test(test_split_list_variable_not_found),
};
--
cgit v1.2.3-18-g5258
From 687fa0ef362dfdacb6ee0a169d7ab0a84e747cc4 Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Fri, 8 Jan 2016 18:53:51 +0100
Subject: fixed copyright
---
LICENSE | 2 +-
src/content-parser.c | 2 +-
src/content-parser.h | 2 +-
src/datetime-parser.c | 2 +-
src/datetime-parser.h | 2 +-
src/error.c | 2 +-
src/error.h | 2 +-
src/file.c | 2 +-
src/file.h | 2 +-
src/loader.c | 2 +-
src/loader.h | 2 +-
src/main.c | 2 +-
src/renderer.c | 2 +-
src/renderer.h | 2 +-
src/source-parser.c | 2 +-
src/source-parser.h | 2 +-
src/template-parser.c | 2 +-
src/template-parser.h | 2 +-
src/utils/mem.c | 2 +-
src/utils/slist.c | 2 +-
src/utils/strings.c | 2 +-
src/utils/trie.c | 2 +-
src/utils/utils.h | 2 +-
tests/check_content_parser.c | 2 +-
tests/check_datetime_parser.c | 2 +-
tests/check_error.c | 2 +-
tests/check_loader.c | 2 +-
tests/check_renderer.c | 2 +-
tests/check_source_parser.c | 2 +-
tests/check_template_parser.c | 2 +-
tests/check_utils.c | 2 +-
31 files changed, 31 insertions(+), 31 deletions(-)
diff --git a/LICENSE b/LICENSE
index 167fbc7..0f0ff43 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2015, Rafael G. Martins
+Copyright (c) 2014-2016, Rafael G. Martins
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/src/content-parser.c b/src/content-parser.c
index f5450d6..b22eb70 100644
--- a/src/content-parser.c
+++ b/src/content-parser.c
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2015 Rafael G. Martins
+ * Copyright (C) 2015-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/src/content-parser.h b/src/content-parser.h
index 2f6b8b9..5802594 100644
--- a/src/content-parser.h
+++ b/src/content-parser.h
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2015 Rafael G. Martins
+ * Copyright (C) 2015-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/src/datetime-parser.c b/src/datetime-parser.c
index 6a2162d..8785a89 100644
--- a/src/datetime-parser.c
+++ b/src/datetime-parser.c
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2015 Rafael G. Martins
+ * Copyright (C) 2015-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/src/datetime-parser.h b/src/datetime-parser.h
index 7f94545..a5087b3 100644
--- a/src/datetime-parser.h
+++ b/src/datetime-parser.h
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2015 Rafael G. Martins
+ * Copyright (C) 2015-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/src/error.c b/src/error.c
index 28396f8..6256873 100644
--- a/src/error.c
+++ b/src/error.c
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2015 Rafael G. Martins
+ * Copyright (C) 2015-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/src/error.h b/src/error.h
index 845a316..caa86b0 100644
--- a/src/error.h
+++ b/src/error.h
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2015 Rafael G. Martins
+ * Copyright (C) 2015-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/src/file.c b/src/file.c
index d660afc..a4c763a 100644
--- a/src/file.c
+++ b/src/file.c
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2015 Rafael G. Martins
+ * Copyright (C) 2015-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/src/file.h b/src/file.h
index 00145ee..97e5274 100644
--- a/src/file.h
+++ b/src/file.h
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2015 Rafael G. Martins
+ * Copyright (C) 2015-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/src/loader.c b/src/loader.c
index 5cd24df..baa81fa 100644
--- a/src/loader.c
+++ b/src/loader.c
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2015 Rafael G. Martins
+ * Copyright (C) 2015-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/src/loader.h b/src/loader.h
index 610aa42..c432e20 100644
--- a/src/loader.h
+++ b/src/loader.h
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2015 Rafael G. Martins
+ * Copyright (C) 2015-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/src/main.c b/src/main.c
index 600a131..f3f990b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2015 Rafael G. Martins
+ * Copyright (C) 2015-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/src/renderer.c b/src/renderer.c
index 2fb60b5..0f5d10a 100644
--- a/src/renderer.c
+++ b/src/renderer.c
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2015 Rafael G. Martins
+ * Copyright (C) 2015-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/src/renderer.h b/src/renderer.h
index d99fea0..15204e6 100644
--- a/src/renderer.h
+++ b/src/renderer.h
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2015 Rafael G. Martins
+ * Copyright (C) 2015-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/src/source-parser.c b/src/source-parser.c
index db0792c..65fdd4e 100644
--- a/src/source-parser.c
+++ b/src/source-parser.c
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2015 Rafael G. Martins
+ * Copyright (C) 2015-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/src/source-parser.h b/src/source-parser.h
index d92b1ce..f359f9e 100644
--- a/src/source-parser.h
+++ b/src/source-parser.h
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2015 Rafael G. Martins
+ * Copyright (C) 2015-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/src/template-parser.c b/src/template-parser.c
index 030ecca..0783254 100644
--- a/src/template-parser.c
+++ b/src/template-parser.c
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2015 Rafael G. Martins
+ * Copyright (C) 2015-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/src/template-parser.h b/src/template-parser.h
index 9da5fff..5add574 100644
--- a/src/template-parser.h
+++ b/src/template-parser.h
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2015 Rafael G. Martins
+ * Copyright (C) 2015-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/src/utils/mem.c b/src/utils/mem.c
index 7c5e0a2..693d555 100644
--- a/src/utils/mem.c
+++ b/src/utils/mem.c
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2014-2015 Rafael G. Martins
+ * Copyright (C) 2014-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/src/utils/slist.c b/src/utils/slist.c
index 3d9b892..9753aa7 100644
--- a/src/utils/slist.c
+++ b/src/utils/slist.c
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2014-2015 Rafael G. Martins
+ * Copyright (C) 2014-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/src/utils/strings.c b/src/utils/strings.c
index 40174a1..6f10d56 100644
--- a/src/utils/strings.c
+++ b/src/utils/strings.c
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2014-2015 Rafael G. Martins
+ * Copyright (C) 2014-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/src/utils/trie.c b/src/utils/trie.c
index 72a62f6..b8c1e63 100644
--- a/src/utils/trie.c
+++ b/src/utils/trie.c
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2014-2015 Rafael G. Martins
+ * Copyright (C) 2014-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/src/utils/utils.h b/src/utils/utils.h
index 5a1505b..49a7735 100644
--- a/src/utils/utils.h
+++ b/src/utils/utils.h
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2014-2015 Rafael G. Martins
+ * Copyright (C) 2014-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/tests/check_content_parser.c b/tests/check_content_parser.c
index dc3485e..8ed9520 100644
--- a/tests/check_content_parser.c
+++ b/tests/check_content_parser.c
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2015 Rafael G. Martins
+ * Copyright (C) 2015-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/tests/check_datetime_parser.c b/tests/check_datetime_parser.c
index 1ac976d..ba5a79d 100644
--- a/tests/check_datetime_parser.c
+++ b/tests/check_datetime_parser.c
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2015 Rafael G. Martins
+ * Copyright (C) 2015-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/tests/check_error.c b/tests/check_error.c
index 17e1c40..d3af9c0 100644
--- a/tests/check_error.c
+++ b/tests/check_error.c
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2015 Rafael G. Martins
+ * Copyright (C) 2015-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/tests/check_loader.c b/tests/check_loader.c
index 03f0ef1..ac8bdb3 100644
--- a/tests/check_loader.c
+++ b/tests/check_loader.c
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2015 Rafael G. Martins
+ * Copyright (C) 2015-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/tests/check_renderer.c b/tests/check_renderer.c
index 014cd84..360f067 100644
--- a/tests/check_renderer.c
+++ b/tests/check_renderer.c
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2015 Rafael G. Martins
+ * Copyright (C) 2015-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/tests/check_source_parser.c b/tests/check_source_parser.c
index 4d8518e..8d6c039 100644
--- a/tests/check_source_parser.c
+++ b/tests/check_source_parser.c
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2015 Rafael G. Martins
+ * Copyright (C) 2015-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/tests/check_template_parser.c b/tests/check_template_parser.c
index 145a27e..f9fd71a 100644
--- a/tests/check_template_parser.c
+++ b/tests/check_template_parser.c
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2015 Rafael G. Martins
+ * Copyright (C) 2015-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
diff --git a/tests/check_utils.c b/tests/check_utils.c
index a42c75a..cb24625 100644
--- a/tests/check_utils.c
+++ b/tests/check_utils.c
@@ -1,6 +1,6 @@
/*
* blogc: A blog compiler.
- * Copyright (C) 2014-2015 Rafael G. Martins
+ * Copyright (C) 2014-2016 Rafael G. Martins
*
* This program can be distributed under the terms of the BSD License.
* See the file LICENSE.
--
cgit v1.2.3-18-g5258
From 170210579bbe1259315eab2c7f5893448b3f961c Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Sat, 9 Jan 2016 23:47:18 +0100
Subject: build: add build-aux/build-windows.sh to tarball
---
Makefile.am | 1 +
1 file changed, 1 insertion(+)
diff --git a/Makefile.am b/Makefile.am
index 78738cc..e143b0b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,6 +12,7 @@ AM_DISTCHECK_CONFIGURE_FLAGS = \
## File listings
EXTRA_DIST = \
+ build-aux/build-windows.sh \
autogen.sh \
LICENSE \
README.md \
--
cgit v1.2.3-18-g5258
From 52ee02d97169ee59072c24e2ac5d717cfaf359fc Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Sun, 10 Jan 2016 01:06:32 +0100
Subject: build: improved windows build script
---
build-aux/build-windows.sh | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/build-aux/build-windows.sh b/build-aux/build-windows.sh
index 267a8aa..bdecc8b 100755
--- a/build-aux/build-windows.sh
+++ b/build-aux/build-windows.sh
@@ -5,24 +5,18 @@
#
# mingw32-gcc mingw64-gcc zip
#
-# This script must be called with the xz source tarball as argument.
+# This script must be called with the xz source tarball and the target version
+# as arguments.
set -ex
-[[ $# -eq 1 ]]
-
-
-get_version() {
- local a=$(basename "${1}")
- a="${a%.tar.xz}"
- echo "${a#blogc-}"
-}
+[[ $# -eq 2 ]]
build() {
- local version=$(get_version "${1}")
- local arch=${2}
+ local version=${2}
+ local arch=${3}
local build_dir="/tmp/blogc_build_${version}_${arch}"
local dest_dir="/tmp/blogc-${version}-w${arch}"
@@ -50,5 +44,5 @@ build() {
for arch in 32 64; do
- build "$1" "${arch}"
+ build "$1" "$2" "${arch}"
done
--
cgit v1.2.3-18-g5258
From 6e44d82d3b3ff6f5376fdafa6ee7fa09fc4f8ffb Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Sun, 10 Jan 2016 02:13:25 +0100
Subject: build: added rpm spec
---
.gitignore | 1 +
blogc.spec.in | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
configure.ac | 1 +
3 files changed, 65 insertions(+)
create mode 100644 blogc.spec.in
diff --git a/.gitignore b/.gitignore
index 65e51f1..2ccfd38 100644
--- a/.gitignore
+++ b/.gitignore
@@ -60,4 +60,5 @@ blogc-*.tar.*
blogc-*.zip
# rpms
+blogc.spec
blogc-*.rpm
diff --git a/blogc.spec.in b/blogc.spec.in
new file mode 100644
index 0000000..96df668
--- /dev/null
+++ b/blogc.spec.in
@@ -0,0 +1,63 @@
+Name: blogc
+Version: @PACKAGE_VERSION@
+Release: 1%{?dist}
+License: BSD
+Group: Applications/Text
+Summary: A blog compiler
+URL: http://blogc.org/
+Source0: https://github.com/blogc/blogc/releases/download/v%{version}/blogc-%{version}.tar.xz
+
+#BuildRequires:
+#Requires:
+
+%description
+blogc(1) is a blog compiler. It converts source files and templates into
+blog/website resources.
+
+
+%prep
+%setup -q -n blogc-%{version}
+
+
+%build
+%configure
+make %{?_smp_mflags}
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+%make_install
+
+
+%files
+%{_mandir}/man*/blogc*
+%{_bindir}/blogc
+
+%doc README.md
+%license LICENSE
+
+
+%changelog
+* Thu Jan 07 2016 Rafael G. Martins 0.6-1
+- New release.
+
+* Thu Dec 03 2015 Rafael G. Martins 0.5.1-1
+- New release.
+
+* Thu Nov 05 2015 Rafael G. Martins 0.5-1
+- New release.
+
+* Sun Oct 25 2015 Rafael G. Martins 0.4-1
+- New release.
+
+* Fri Oct 16 2015 Rafael G. Martins 0.3-1
+- New release.
+
+* Thu Oct 08 2015 Rafael G. Martins 0.2.1-1
+- New release.
+
+* Wed Sep 16 2015 Rafael G. Martins 0.1-1
+- First stable release.
+
+* Mon Sep 14 2015 Rafael G. Martins 0.1-0.1.beta4
+- Initial package.
diff --git a/configure.ac b/configure.ac
index ffb61ac..5f6859f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -101,6 +101,7 @@ LT_LIB_M
AC_CONFIG_FILES([
Makefile
+ blogc.spec
])
AC_OUTPUT
--
cgit v1.2.3-18-g5258
From 1c819d729177f6569febb962955dd8098ef6b35b Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Sun, 10 Jan 2016 03:01:11 +0100
Subject: build: version bump
---
blogc.spec.in | 3 +++
configure.ac | 2 +-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/blogc.spec.in b/blogc.spec.in
index 96df668..f10e7fc 100644
--- a/blogc.spec.in
+++ b/blogc.spec.in
@@ -38,6 +38,9 @@ rm -rf $RPM_BUILD_ROOT
%changelog
+* Sun Jan 10 2016 Rafael G. Martins 0.6.1-1
+- New release.
+
* Thu Jan 07 2016 Rafael G. Martins 0.6-1
- New release.
diff --git a/configure.ac b/configure.ac
index 5f6859f..e43633d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
AC_PREREQ([2.69])
-AC_INIT([blogc], [0.6], [https://github.com/blogc/blogc], [blogc],
+AC_INIT([blogc], [0.6.1], [https://github.com/blogc/blogc], [blogc],
[https://blogc.rgm.io])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
--
cgit v1.2.3-18-g5258
From 5e53ba7406e65b51ec59aad634b6baf7154e1ad3 Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Wed, 13 Jan 2016 19:31:32 +0100
Subject: build: added git-version-gen support
---
.gitignore | 4 +
Makefile.am | 15 ++++
build-aux/git-version-gen | 225 ++++++++++++++++++++++++++++++++++++++++++++++
configure.ac | 4 +-
4 files changed, 246 insertions(+), 2 deletions(-)
create mode 100755 build-aux/git-version-gen
diff --git a/.gitignore b/.gitignore
index 2ccfd38..01d2647 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,6 +33,7 @@ Makefile.in
.dirstamp
/build-aux/*
!/build-aux/build-windows.sh
+!/build-aux/git-version-gen
# installed .m4 files
/m4/*.m4
@@ -62,3 +63,6 @@ blogc-*.zip
# rpms
blogc.spec
blogc-*.rpm
+
+# git-version-gen
+/.version
diff --git a/Makefile.am b/Makefile.am
index e143b0b..7b52fa0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -13,6 +13,8 @@ AM_DISTCHECK_CONFIGURE_FLAGS = \
EXTRA_DIST = \
build-aux/build-windows.sh \
+ build-aux/git-version-gen \
+ $(top_srcdir)/.version \
autogen.sh \
LICENSE \
README.md \
@@ -24,6 +26,10 @@ CLEANFILES = \
MAINTAINERCLEANFILES = \
$(NULL)
+BUILT_SOURCES = \
+ $(top_srcdir)/.version \
+ $(NULL)
+
noinst_HEADERS = \
src/content-parser.h \
src/datetime-parser.h \
@@ -308,6 +314,15 @@ TESTS = \
$(check_PROGRAMS)
+## Helpers: git-version-gen
+
+$(top_srcdir)/.version:
+ echo $(VERSION) > $@-t && mv $@-t $@
+
+dist-hook:
+ echo $(VERSION) > $(distdir)/.tarball-version
+
+
## Helpers: Valgrind runner
if USE_VALGRIND
diff --git a/build-aux/git-version-gen b/build-aux/git-version-gen
new file mode 100755
index 0000000..3468247
--- /dev/null
+++ b/build-aux/git-version-gen
@@ -0,0 +1,225 @@
+#!/bin/sh
+# Print a version string.
+scriptversion=2012-12-31.23; # UTC
+
+# Copyright (C) 2007-2013 Free Software Foundation, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+# This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/.
+# It may be run two ways:
+# - from a git repository in which the "git describe" command below
+# produces useful output (thus requiring at least one signed tag)
+# - from a non-git-repo directory containing a .tarball-version file, which
+# presumes this script is invoked like "./git-version-gen .tarball-version".
+
+# In order to use intra-version strings in your project, you will need two
+# separate generated version string files:
+#
+# .tarball-version - present only in a distribution tarball, and not in
+# a checked-out repository. Created with contents that were learned at
+# the last time autoconf was run, and used by git-version-gen. Must not
+# be present in either $(srcdir) or $(builddir) for git-version-gen to
+# give accurate answers during normal development with a checked out tree,
+# but must be present in a tarball when there is no version control system.
+# Therefore, it cannot be used in any dependencies. GNUmakefile has
+# hooks to force a reconfigure at distribution time to get the value
+# correct, without penalizing normal development with extra reconfigures.
+#
+# .version - present in a checked-out repository and in a distribution
+# tarball. Usable in dependencies, particularly for files that don't
+# want to depend on config.h but do want to track version changes.
+# Delete this file prior to any autoconf run where you want to rebuild
+# files to pick up a version string change; and leave it stale to
+# minimize rebuild time after unrelated changes to configure sources.
+#
+# As with any generated file in a VC'd directory, you should add
+# /.version to .gitignore, so that you don't accidentally commit it.
+# .tarball-version is never generated in a VC'd directory, so needn't
+# be listed there.
+#
+# Use the following line in your configure.ac, so that $(VERSION) will
+# automatically be up-to-date each time configure is run (and note that
+# since configure.ac no longer includes a version string, Makefile rules
+# should not depend on configure.ac for version updates).
+#
+# AC_INIT([GNU project],
+# m4_esyscmd([build-aux/git-version-gen .tarball-version]),
+# [bug-project@example])
+#
+# Then use the following lines in your Makefile.am, so that .version
+# will be present for dependencies, and so that .version and
+# .tarball-version will exist in distribution tarballs.
+#
+# EXTRA_DIST = $(top_srcdir)/.version
+# BUILT_SOURCES = $(top_srcdir)/.version
+# $(top_srcdir)/.version:
+# echo $(VERSION) > $@-t && mv $@-t $@
+# dist-hook:
+# echo $(VERSION) > $(distdir)/.tarball-version
+
+
+me=$0
+
+version="git-version-gen $scriptversion
+
+Copyright 2011 Free Software Foundation, Inc.
+There is NO warranty. You may redistribute this software
+under the terms of the GNU General Public License.
+For more information about these matters, see the files named COPYING."
+
+usage="\
+Usage: $me [OPTION]... \$srcdir/.tarball-version [TAG-NORMALIZATION-SED-SCRIPT]
+Print a version string.
+
+Options:
+
+ --prefix prefix of git tags (default 'v')
+ --fallback fallback version to use if \"git --version\" fails
+
+ --help display this help and exit
+ --version output version information and exit
+
+Running without arguments will suffice in most cases."
+
+prefix=v
+fallback=
+
+while test $# -gt 0; do
+ case $1 in
+ --help) echo "$usage"; exit 0;;
+ --version) echo "$version"; exit 0;;
+ --prefix) shift; prefix="$1";;
+ --fallback) shift; fallback="$1";;
+ -*)
+ echo "$0: Unknown option '$1'." >&2
+ echo "$0: Try '--help' for more information." >&2
+ exit 1;;
+ *)
+ if test "x$tarball_version_file" = x; then
+ tarball_version_file="$1"
+ elif test "x$tag_sed_script" = x; then
+ tag_sed_script="$1"
+ else
+ echo "$0: extra non-option argument '$1'." >&2
+ exit 1
+ fi;;
+ esac
+ shift
+done
+
+if test "x$tarball_version_file" = x; then
+ echo "$usage"
+ exit 1
+fi
+
+tag_sed_script="${tag_sed_script:-s/x/x/}"
+
+nl='
+'
+
+# Avoid meddling by environment variable of the same name.
+v=
+v_from_git=
+
+# First see if there is a tarball-only version file.
+# then try "git describe", then default.
+if test -f $tarball_version_file
+then
+ v=`cat $tarball_version_file` || v=
+ case $v in
+ *$nl*) v= ;; # reject multi-line output
+ [0-9]*) ;;
+ *) v= ;;
+ esac
+ test "x$v" = x \
+ && echo "$0: WARNING: $tarball_version_file is missing or damaged" 1>&2
+fi
+
+if test "x$v" != x
+then
+ : # use $v
+# Otherwise, if there is at least one git commit involving the working
+# directory, and "git describe" output looks sensible, use that to
+# derive a version string.
+elif test "`git log -1 --pretty=format:x . 2>&1`" = x \
+ && v=`git describe --abbrev=4 --match="$prefix*" HEAD 2>/dev/null \
+ || git describe --abbrev=4 HEAD 2>/dev/null` \
+ && v=`printf '%s\n' "$v" | sed "$tag_sed_script"` \
+ && case $v in
+ $prefix[0-9]*) ;;
+ *) (exit 1) ;;
+ esac
+then
+ # Is this a new git that lists number of commits since the last
+ # tag or the previous older version that did not?
+ # Newer: v6.10-77-g0f8faeb
+ # Older: v6.10-g0f8faeb
+ case $v in
+ *-*-*) : git describe is okay three part flavor ;;
+ *-*)
+ : git describe is older two part flavor
+ # Recreate the number of commits and rewrite such that the
+ # result is the same as if we were using the newer version
+ # of git describe.
+ vtag=`echo "$v" | sed 's/-.*//'`
+ commit_list=`git rev-list "$vtag"..HEAD 2>/dev/null` \
+ || { commit_list=failed;
+ echo "$0: WARNING: git rev-list failed" 1>&2; }
+ numcommits=`echo "$commit_list" | wc -l`
+ v=`echo "$v" | sed "s/\(.*\)-\(.*\)/\1-$numcommits-\2/"`;
+ test "$commit_list" = failed && v=UNKNOWN
+ ;;
+ esac
+
+ # Change the first '-' to a '.', so version-comparing tools work properly.
+ # Remove the "g" in git describe's output string, to save a byte.
+ v=`echo "$v" | sed 's/-/./;s/\(.*\)-g/\1-/'`;
+ v_from_git=1
+elif test "x$fallback" = x || git --version >/dev/null 2>&1; then
+ v=UNKNOWN
+else
+ v=$fallback
+fi
+
+v=`echo "$v" |sed "s/^$prefix//"`
+
+# Test whether to append the "-dirty" suffix only if the version
+# string we're using came from git. I.e., skip the test if it's "UNKNOWN"
+# or if it came from .tarball-version.
+if test "x$v_from_git" != x; then
+ # Don't declare a version "dirty" merely because a time stamp has changed.
+ git update-index --refresh > /dev/null 2>&1
+
+ dirty=`exec 2>/dev/null;git diff-index --name-only HEAD` || dirty=
+ case "$dirty" in
+ '') ;;
+ *) # Append the suffix only if there isn't one already.
+ case $v in
+ *-dirty) ;;
+ *) v="$v-dirty" ;;
+ esac ;;
+ esac
+fi
+
+# Omit the trailing newline, so that m4_esyscmd can use the result directly.
+echo "$v" | tr -d "$nl"
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/configure.ac b/configure.ac
index e43633d..f837f1b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
AC_PREREQ([2.69])
-AC_INIT([blogc], [0.6.1], [https://github.com/blogc/blogc], [blogc],
- [https://blogc.rgm.io])
+AC_INIT([blogc], m4_esyscmd([build-aux/git-version-gen .tarball-version]),
+ [https://github.com/blogc/blogc], [blogc], [https://blogc.rgm.io])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
--
cgit v1.2.3-18-g5258
From f7aa4a3269a21f4d0c83f11a0aef4ccf821ce6e2 Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Thu, 14 Jan 2016 03:50:42 +0100
Subject: template-parser: added whitespace cleaners. needs more tests and docs
---
src/template-parser.c | 99 +++++++++++++++++++++++++++++++++++++------
src/template-parser.h | 5 +++
src/utils/strings.c | 45 ++++++++++++++++----
src/utils/utils.h | 2 +
tests/check_template_parser.c | 48 +++++++++++++++------
tests/check_utils.c | 55 ++++++++++++++++++++++++
6 files changed, 218 insertions(+), 36 deletions(-)
diff --git a/src/template-parser.c b/src/template-parser.c
index 0783254..1d9046e 100644
--- a/src/template-parser.c
+++ b/src/template-parser.c
@@ -22,6 +22,7 @@ typedef enum {
TEMPLATE_START = 1,
TEMPLATE_OPEN_BRACKET,
TEMPLATE_BLOCK_START,
+ TEMPLATE_BLOCK_START_WHITESPACE_CLEANER,
TEMPLATE_BLOCK_TYPE,
TEMPLATE_BLOCK_BLOCK_TYPE_START,
TEMPLATE_BLOCK_BLOCK_TYPE,
@@ -34,6 +35,7 @@ typedef enum {
TEMPLATE_BLOCK_IF_VARIABLE_OPERAND,
TEMPLATE_BLOCK_FOREACH_START,
TEMPLATE_BLOCK_FOREACH_VARIABLE,
+ TEMPLATE_BLOCK_END_WHITESPACE_CLEANER,
TEMPLATE_BLOCK_END,
TEMPLATE_VARIABLE_START,
TEMPLATE_VARIABLE,
@@ -72,6 +74,20 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
b_slist_t *stmts = NULL;
blogc_template_stmt_t *stmt = NULL;
+ /*
+ * this is a reference to the content of previous node in the singly-linked
+ * list. The "correct" solution here would be implement a doubly-linked
+ * list, but here are a few reasons to avoid it:
+ *
+ * - i'm too tired to implement it :P
+ * - template parser never walk backwards, then the list itself does not
+ * need to know its previous node.
+ */
+ blogc_template_stmt_t *previous = NULL;
+
+ bool lstrip_next = false;
+ char *tmp = 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;
@@ -86,10 +102,20 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
if (last) {
stmt = b_malloc(sizeof(blogc_template_stmt_t));
stmt->type = type;
- stmt->value = b_strndup(src + start, src_len - start);
+ if (lstrip_next) {
+ tmp = b_strndup(src + start, src_len - start);
+ stmt->value = b_strdup(b_str_lstrip(tmp));
+ free(tmp);
+ tmp = NULL;
+ lstrip_next = false;
+ }
+ else {
+ stmt->value = b_strndup(src + start, src_len - start);
+ }
stmt->op = 0;
stmt->value2 = NULL;
stmts = b_slist_append(stmts, stmt);
+ previous = stmt;
stmt = NULL;
}
if (c == '{') {
@@ -101,16 +127,26 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
case TEMPLATE_OPEN_BRACKET:
if (c == '%' || c == '{') {
if (c == '%')
- state = TEMPLATE_BLOCK_START;
+ state = TEMPLATE_BLOCK_START_WHITESPACE_CLEANER;
else
state = TEMPLATE_VARIABLE_START;
if (end > start) {
stmt = b_malloc(sizeof(blogc_template_stmt_t));
stmt->type = type;
- stmt->value = b_strndup(src + start, end - start);
+ if (lstrip_next) {
+ tmp = b_strndup(src + start, end - start);
+ stmt->value = b_strdup(b_str_lstrip(tmp));
+ free(tmp);
+ tmp = NULL;
+ lstrip_next = false;
+ }
+ else {
+ stmt->value = b_strndup(src + start, end - start);
+ }
stmt->op = 0;
stmt->value2 = NULL;
stmts = b_slist_append(stmts, stmt);
+ previous = stmt;
stmt = NULL;
}
break;
@@ -118,6 +154,18 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
state = TEMPLATE_START;
break;
+ case TEMPLATE_BLOCK_START_WHITESPACE_CLEANER:
+ if (c == '-') {
+ if ((previous != NULL) &&
+ (previous->type == BLOGC_TEMPLATE_CONTENT_STMT))
+ {
+ previous->value = b_str_rstrip(previous->value); // does not need copy
+ }
+ state = TEMPLATE_BLOCK_START;
+ break;
+ }
+ state = TEMPLATE_BLOCK_START;
+
case TEMPLATE_BLOCK_START:
if (c == ' ')
break;
@@ -126,6 +174,13 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
start = current;
break;
}
+ if (c == '-') {
+ *err = blogc_error_parser(BLOGC_ERROR_TEMPLATE_PARSER, src,
+ src_len, current,
+ "Invalid statement syntax. Duplicated whitespace "
+ "cleaner before statement.");
+ break;
+ }
*err = blogc_error_parser(BLOGC_ERROR_TEMPLATE_PARSER, src,
src_len, current,
"Invalid statement syntax. Must begin with lowercase letter.");
@@ -152,7 +207,7 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
(0 == strncmp("endblock", src + start, 8)))
{
if (block_state != BLOCK_CLOSED) {
- state = TEMPLATE_BLOCK_END;
+ state = TEMPLATE_BLOCK_END_WHITESPACE_CLEANER;
type = BLOGC_TEMPLATE_ENDBLOCK_STMT;
block_state = BLOCK_CLOSED;
break;
@@ -193,7 +248,7 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
(0 == strncmp("endif", src + start, 5)))
{
if (if_count > 0) {
- state = TEMPLATE_BLOCK_END;
+ state = TEMPLATE_BLOCK_END_WHITESPACE_CLEANER;
type = BLOGC_TEMPLATE_ENDIF_STMT;
if_count--;
break;
@@ -223,7 +278,7 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
(0 == strncmp("endforeach", src + start, 10)))
{
if (foreach_open) {
- state = TEMPLATE_BLOCK_END;
+ state = TEMPLATE_BLOCK_END_WHITESPACE_CLEANER;
type = BLOGC_TEMPLATE_ENDFOREACH_STMT;
foreach_open = false;
break;
@@ -264,7 +319,7 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
{
block_state = BLOCK_ENTRY;
end = current;
- state = TEMPLATE_BLOCK_END;
+ state = TEMPLATE_BLOCK_END_WHITESPACE_CLEANER;
break;
}
else if ((current - start == 7) &&
@@ -272,7 +327,7 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
{
block_state = BLOCK_LISTING;
end = current;
- state = TEMPLATE_BLOCK_END;
+ state = TEMPLATE_BLOCK_END_WHITESPACE_CLEANER;
break;
}
else if ((current - start == 12) &&
@@ -280,7 +335,7 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
{
block_state = BLOCK_LISTING_ONCE;
end = current;
- state = TEMPLATE_BLOCK_END;
+ state = TEMPLATE_BLOCK_END_WHITESPACE_CLEANER;
break;
}
}
@@ -311,7 +366,7 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
if (type == BLOGC_TEMPLATE_IF_STMT)
state = TEMPLATE_BLOCK_IF_OPERATOR_START;
else
- state = TEMPLATE_BLOCK_END;
+ state = TEMPLATE_BLOCK_END_WHITESPACE_CLEANER;
break;
}
*err = blogc_error_parser(BLOGC_ERROR_TEMPLATE_PARSER, src,
@@ -361,14 +416,14 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
break;
if (c == '"' && src[current - 1] == '\\')
break;
- state = TEMPLATE_BLOCK_END;
+ state = TEMPLATE_BLOCK_END_WHITESPACE_CLEANER;
end2 = current + 1;
break;
case TEMPLATE_BLOCK_IF_VARIABLE_OPERAND:
if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')
break;
- state = TEMPLATE_BLOCK_END;
+ state = TEMPLATE_BLOCK_END_WHITESPACE_CLEANER;
end2 = current;
break;
@@ -391,7 +446,7 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
break;
if (c == ' ') {
end = current;
- state = TEMPLATE_BLOCK_END;
+ state = TEMPLATE_BLOCK_END_WHITESPACE_CLEANER;
break;
}
*err = blogc_error_parser(BLOGC_ERROR_TEMPLATE_PARSER, src,
@@ -400,13 +455,28 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
"number or '_'.");
break;
- case TEMPLATE_BLOCK_END:
+ case TEMPLATE_BLOCK_END_WHITESPACE_CLEANER:
if (c == ' ')
break;
+ if (c == '-') {
+ lstrip_next = true;
+ state = TEMPLATE_BLOCK_END;
+ break;
+ }
+ state = TEMPLATE_BLOCK_END;
+
+ case TEMPLATE_BLOCK_END:
if (c == '%') {
state = TEMPLATE_CLOSE_BRACKET;
break;
}
+ if (c == '-') {
+ *err = blogc_error_parser(BLOGC_ERROR_TEMPLATE_PARSER, src,
+ src_len, current,
+ "Invalid statement syntax. Duplicated whitespace "
+ "cleaner after statement.");
+ break;
+ }
*err = blogc_error_parser(BLOGC_ERROR_TEMPLATE_PARSER, src,
src_len, current,
"Invalid statement syntax. Must end with '%%}'.");
@@ -502,6 +572,7 @@ blogc_template_parse(const char *src, size_t src_len, blogc_error_t **err)
end2 = 0;
}
stmts = b_slist_append(stmts, stmt);
+ previous = stmt;
stmt = NULL;
state = TEMPLATE_START;
type = BLOGC_TEMPLATE_CONTENT_STMT;
diff --git a/src/template-parser.h b/src/template-parser.h
index 5add574..6cd2c80 100644
--- a/src/template-parser.h
+++ b/src/template-parser.h
@@ -12,6 +12,11 @@
#include "utils/utils.h"
#include "error.h"
+/*
+ * note: whitespace cleaners are NOT added to ast. we fix strings right during
+ * template parsing. renderer does not need to care about it, for the sake of
+ * simplicity.
+ */
typedef enum {
BLOGC_TEMPLATE_IFDEF_STMT = 1,
BLOGC_TEMPLATE_IFNDEF_STMT,
diff --git a/src/utils/strings.c b/src/utils/strings.c
index 6f10d56..846ae95 100644
--- a/src/utils/strings.c
+++ b/src/utils/strings.c
@@ -103,22 +103,44 @@ b_str_ends_with(const char *str, const char *suffix)
char*
-b_str_strip(char *str)
+b_str_lstrip(char *str)
{
if (str == NULL)
- return str;
+ return NULL;
+ int i;
+ size_t str_len = strlen(str);
+ for (i = 0; i < str_len; i++) {
+ if ((str[i] != ' ') && (str[i] != '\t') && (str[i] != '\n') &&
+ (str[i] != '\r') && (str[i] != '\t'))
+ {
+ str += i;
+ break;
+ }
+ if (i == str_len - 1) {
+ str += str_len;
+ break;
+ }
+ }
+ return str;
+}
+
+
+char*
+b_str_rstrip(char *str)
+{
+ if (str == NULL)
+ return NULL;
int i;
size_t str_len = strlen(str);
for (i = str_len - 1; i >= 0; i--) {
- if (!isspace(str[i])) {
+ if ((str[i] != ' ') && (str[i] != '\t') && (str[i] != '\n') &&
+ (str[i] != '\r') && (str[i] != '\t'))
+ {
str[i + 1] = '\0';
break;
}
- }
- str_len = strlen(str);
- for (i = 0; i < str_len; i++) {
- if (!isspace(str[i])) {
- str = str + i;
+ if (i == 0) {
+ str[0] = '\0';
break;
}
}
@@ -126,6 +148,13 @@ b_str_strip(char *str)
}
+char*
+b_str_strip(char *str)
+{
+ return b_str_lstrip(b_str_rstrip(str));
+}
+
+
char**
b_str_split(const char *str, char c, unsigned int max_pieces)
{
diff --git a/src/utils/utils.h b/src/utils/utils.h
index 49a7735..dc67497 100644
--- a/src/utils/utils.h
+++ b/src/utils/utils.h
@@ -50,6 +50,8 @@ char* b_strdup_vprintf(const char *format, va_list ap);
char* b_strdup_printf(const char *format, ...);
bool b_str_starts_with(const char *str, const char *prefix);
bool b_str_ends_with(const char *str, const char *suffix);
+char* b_str_lstrip(char *str);
+char* b_str_rstrip(char *str);
char* b_str_strip(char *str);
char** b_str_split(const char *str, char c, unsigned int max_pieces);
char* b_str_replace(const char *str, const char search, const char *replace);
diff --git a/tests/check_template_parser.c b/tests/check_template_parser.c
index f9fd71a..f655896 100644
--- a/tests/check_template_parser.c
+++ b/tests/check_template_parser.c
@@ -51,27 +51,27 @@ test_template_parse(void **state)
const char *a =
"Test\n"
"\n"
- " {% block entry %}\n"
+ " {%- block entry -%}\n"
"{% ifdef CHUNDA %}\n"
"bola\n"
"{% endif %}\n"
"{% ifndef BOLA %}\n"
"bolao\n"
- "{% endif %}\n"
+ "{%- endif %}\n"
"{% endblock %}\n"
"{% block listing %}{{ BOLA }}{% endblock %}\n"
"{% block listing_once %}asd{% endblock %}\n"
- "{% foreach BOLA %}hahaha{% endforeach %}\n"
+ "{%- foreach BOLA %}hahaha{% endforeach %}\n"
"{% if BOLA == \"1\\\"0\" %}aee{% endif %}";
blogc_error_t *err = NULL;
b_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
assert_null(err);
assert_non_null(stmts);
- blogc_assert_template_stmt(stmts, "Test\n\n ",
+ blogc_assert_template_stmt(stmts, "Test",
BLOGC_TEMPLATE_CONTENT_STMT);
blogc_assert_template_stmt(stmts->next, "entry",
BLOGC_TEMPLATE_BLOCK_STMT);
- blogc_assert_template_stmt(stmts->next->next, "\n",
+ blogc_assert_template_stmt(stmts->next->next, "",
BLOGC_TEMPLATE_CONTENT_STMT);
blogc_assert_template_stmt(stmts->next->next->next, "CHUNDA",
BLOGC_TEMPLATE_IFDEF_STMT);
@@ -83,7 +83,7 @@ test_template_parse(void **state)
BLOGC_TEMPLATE_CONTENT_STMT);
b_slist_t *tmp = stmts->next->next->next->next->next->next->next;
blogc_assert_template_stmt(tmp, "BOLA", BLOGC_TEMPLATE_IFNDEF_STMT);
- blogc_assert_template_stmt(tmp->next, "\nbolao\n", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next, "\nbolao", 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);
@@ -105,7 +105,7 @@ test_template_parse(void **state)
blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next->next,
NULL, BLOGC_TEMPLATE_ENDBLOCK_STMT);
blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next->next->next,
- "\n", BLOGC_TEMPLATE_CONTENT_STMT);
+ "", BLOGC_TEMPLATE_CONTENT_STMT);
tmp = tmp->next->next->next->next->next->next->next->next->next->next;
blogc_assert_template_stmt(tmp, "BOLA", BLOGC_TEMPLATE_FOREACH_STMT);
blogc_assert_template_stmt(tmp->next, "hahaha",
@@ -131,27 +131,27 @@ test_template_parse_crlf(void **state)
const char *a =
"Test\r\n"
"\r\n"
- " {% block entry %}\r\n"
+ " {%- block entry -%}\r\n"
"{% ifdef CHUNDA %}\r\n"
"bola\r\n"
"{% endif %}\r\n"
"{% ifndef BOLA %}\r\n"
"bolao\r\n"
- "{% endif %}\r\n"
+ "{%- endif %}\r\n"
"{% endblock %}\r\n"
"{% block listing %}{{ BOLA }}{% endblock %}\r\n"
"{% block listing_once %}asd{% endblock %}\r\n"
- "{% foreach BOLA %}hahaha{% endforeach %}\r\n"
+ "{%- foreach BOLA %}hahaha{% endforeach %}\r\n"
"{% if BOLA == \"1\\\"0\" %}aee{% endif %}";
blogc_error_t *err = NULL;
b_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
assert_null(err);
assert_non_null(stmts);
- blogc_assert_template_stmt(stmts, "Test\r\n\r\n ",
+ blogc_assert_template_stmt(stmts, "Test",
BLOGC_TEMPLATE_CONTENT_STMT);
blogc_assert_template_stmt(stmts->next, "entry",
BLOGC_TEMPLATE_BLOCK_STMT);
- blogc_assert_template_stmt(stmts->next->next, "\r\n",
+ blogc_assert_template_stmt(stmts->next->next, "",
BLOGC_TEMPLATE_CONTENT_STMT);
blogc_assert_template_stmt(stmts->next->next->next, "CHUNDA",
BLOGC_TEMPLATE_IFDEF_STMT);
@@ -163,7 +163,7 @@ test_template_parse_crlf(void **state)
BLOGC_TEMPLATE_CONTENT_STMT);
b_slist_t *tmp = stmts->next->next->next->next->next->next->next;
blogc_assert_template_stmt(tmp, "BOLA", BLOGC_TEMPLATE_IFNDEF_STMT);
- blogc_assert_template_stmt(tmp->next, "\r\nbolao\r\n", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next, "\r\nbolao", BLOGC_TEMPLATE_CONTENT_STMT);
blogc_assert_template_stmt(tmp->next->next, NULL, BLOGC_TEMPLATE_ENDIF_STMT);
blogc_assert_template_stmt(tmp->next->next->next, "\r\n",
BLOGC_TEMPLATE_CONTENT_STMT);
@@ -185,7 +185,7 @@ test_template_parse_crlf(void **state)
blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next->next,
NULL, BLOGC_TEMPLATE_ENDBLOCK_STMT);
blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next->next->next,
- "\r\n", BLOGC_TEMPLATE_CONTENT_STMT);
+ "", BLOGC_TEMPLATE_CONTENT_STMT);
tmp = tmp->next->next->next->next->next->next->next->next->next->next;
blogc_assert_template_stmt(tmp, "BOLA", BLOGC_TEMPLATE_FOREACH_STMT);
blogc_assert_template_stmt(tmp->next, "hahaha",
@@ -381,6 +381,26 @@ test_template_parse_invalid_block_start(void **state)
"Invalid statement syntax. Must begin with lowercase letter.\n"
"Error occurred near line 1, position 4: {% ASD %}");
blogc_error_free(err);
+ a = "{%-- block entry %}\n";
+ err = NULL;
+ 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 statement syntax. Duplicated whitespace cleaner before statement.\n"
+ "Error occurred near line 1, position 4: {%-- block entry %}");
+ blogc_error_free(err);
+ a = "{% block entry --%}\n";
+ err = NULL;
+ 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 statement syntax. Duplicated whitespace cleaner after statement.\n"
+ "Error occurred near line 1, position 17: {% block entry --%}");
+ blogc_error_free(err);
}
diff --git a/tests/check_utils.c b/tests/check_utils.c
index cb24625..a511dda 100644
--- a/tests/check_utils.c
+++ b/tests/check_utils.c
@@ -128,6 +128,50 @@ test_str_ends_with(void **state)
}
+static void
+test_str_lstrip(void **state)
+{
+ char *str = b_strdup(" \tbola\n \t");
+ assert_string_equal(b_str_lstrip(str), "bola\n \t");
+ free(str);
+ str = b_strdup("guda");
+ assert_string_equal(b_str_lstrip(str), "guda");
+ free(str);
+ str = b_strdup("\n");
+ assert_string_equal(b_str_lstrip(str), "");
+ free(str);
+ str = b_strdup("\t \n");
+ assert_string_equal(b_str_lstrip(str), "");
+ free(str);
+ str = b_strdup("");
+ assert_string_equal(b_str_lstrip(str), "");
+ free(str);
+ assert_null(b_str_lstrip(NULL));
+}
+
+
+static void
+test_str_rstrip(void **state)
+{
+ char *str = b_strdup(" \tbola\n \t");
+ assert_string_equal(b_str_rstrip(str), " \tbola");
+ free(str);
+ str = b_strdup("guda");
+ assert_string_equal(b_str_rstrip(str), "guda");
+ free(str);
+ str = b_strdup("\n");
+ assert_string_equal(b_str_rstrip(str), "");
+ free(str);
+ str = b_strdup("\t \n");
+ assert_string_equal(b_str_rstrip(str), "");
+ free(str);
+ str = b_strdup("");
+ assert_string_equal(b_str_rstrip(str), "");
+ free(str);
+ assert_null(b_str_rstrip(NULL));
+}
+
+
static void
test_str_strip(void **state)
{
@@ -137,6 +181,15 @@ test_str_strip(void **state)
str = b_strdup("guda");
assert_string_equal(b_str_strip(str), "guda");
free(str);
+ str = b_strdup("\n");
+ assert_string_equal(b_str_strip(str), "");
+ free(str);
+ str = b_strdup("\t \n");
+ assert_string_equal(b_str_strip(str), "");
+ free(str);
+ str = b_strdup("");
+ assert_string_equal(b_str_strip(str), "");
+ free(str);
assert_null(b_str_strip(NULL));
}
@@ -799,6 +852,8 @@ main(void)
unit_test(test_strdup_printf),
unit_test(test_str_starts_with),
unit_test(test_str_ends_with),
+ unit_test(test_str_lstrip),
+ unit_test(test_str_rstrip),
unit_test(test_str_strip),
unit_test(test_str_split),
unit_test(test_str_replace),
--
cgit v1.2.3-18-g5258
From a8cde98ad6b747142ea1798f00a6b8c11b208709 Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Thu, 14 Jan 2016 21:42:52 +0100
Subject: utils: string: strip form-feed and vertical-tab chars as whitespaces
---
src/utils/strings.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/utils/strings.c b/src/utils/strings.c
index 846ae95..3151612 100644
--- a/src/utils/strings.c
+++ b/src/utils/strings.c
@@ -111,7 +111,8 @@ b_str_lstrip(char *str)
size_t str_len = strlen(str);
for (i = 0; i < str_len; i++) {
if ((str[i] != ' ') && (str[i] != '\t') && (str[i] != '\n') &&
- (str[i] != '\r') && (str[i] != '\t'))
+ (str[i] != '\r') && (str[i] != '\t') && (str[i] != '\f') &&
+ (str[i] != '\v'))
{
str += i;
break;
@@ -134,7 +135,8 @@ b_str_rstrip(char *str)
size_t str_len = strlen(str);
for (i = str_len - 1; i >= 0; i--) {
if ((str[i] != ' ') && (str[i] != '\t') && (str[i] != '\n') &&
- (str[i] != '\r') && (str[i] != '\t'))
+ (str[i] != '\r') && (str[i] != '\t') && (str[i] != '\f') &&
+ (str[i] != '\v'))
{
str[i + 1] = '\0';
break;
--
cgit v1.2.3-18-g5258
From 542b1d30cca5d6c17b662438d594a91b864ccc56 Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Thu, 14 Jan 2016 21:43:39 +0100
Subject: man: added documentation about whitespace control
---
man/blogc-template.7.ronn | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/man/blogc-template.7.ronn b/man/blogc-template.7.ronn
index 3a665ab..bd38618 100644
--- a/man/blogc-template.7.ronn
+++ b/man/blogc-template.7.ronn
@@ -199,6 +199,19 @@ iteration.
If the value of the `TAGS` variable is "item1 item2 item3", this template is
rendered 3 times, one for each item value.
+## WHITESPACE CONTROL
+
+Users can control how whitespaces (space, form-feed (`\f`), newline (`\n`),
+carriage return (`\r`), horizontal tab (`\t`), and vertical tab (`\v`)) are
+handled before and after statements delimited with `{%` and `%}` sequences,
+respectively.
+
+Adding a minus sign (`-`) after a `{%` sequence (`{%-`) will remove whitespaces
+before the sequence and after the last non-whitespace character before the sequence.
+
+Adding a minus sign (`-`) before a `%}` sequence (`-%}`) will remove whitespaces
+after the sequence and before the first non-whitespace character after the sequence.
+
## BUGS
The template content is handled by handwritten parsers, that even being well
--
cgit v1.2.3-18-g5258
From 8e01ccec4837027a12a4bfc6a54e3c09440169a9 Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Thu, 14 Jan 2016 21:44:52 +0100
Subject: Revert "build: added git-version-gen support"
This reverts commit 5e53ba7406e65b51ec59aad634b6baf7154e1ad3.
---
.gitignore | 4 -
Makefile.am | 15 ----
build-aux/git-version-gen | 225 ----------------------------------------------
configure.ac | 4 +-
4 files changed, 2 insertions(+), 246 deletions(-)
delete mode 100755 build-aux/git-version-gen
diff --git a/.gitignore b/.gitignore
index 01d2647..2ccfd38 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,7 +33,6 @@ Makefile.in
.dirstamp
/build-aux/*
!/build-aux/build-windows.sh
-!/build-aux/git-version-gen
# installed .m4 files
/m4/*.m4
@@ -63,6 +62,3 @@ blogc-*.zip
# rpms
blogc.spec
blogc-*.rpm
-
-# git-version-gen
-/.version
diff --git a/Makefile.am b/Makefile.am
index 7b52fa0..e143b0b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -13,8 +13,6 @@ AM_DISTCHECK_CONFIGURE_FLAGS = \
EXTRA_DIST = \
build-aux/build-windows.sh \
- build-aux/git-version-gen \
- $(top_srcdir)/.version \
autogen.sh \
LICENSE \
README.md \
@@ -26,10 +24,6 @@ CLEANFILES = \
MAINTAINERCLEANFILES = \
$(NULL)
-BUILT_SOURCES = \
- $(top_srcdir)/.version \
- $(NULL)
-
noinst_HEADERS = \
src/content-parser.h \
src/datetime-parser.h \
@@ -314,15 +308,6 @@ TESTS = \
$(check_PROGRAMS)
-## Helpers: git-version-gen
-
-$(top_srcdir)/.version:
- echo $(VERSION) > $@-t && mv $@-t $@
-
-dist-hook:
- echo $(VERSION) > $(distdir)/.tarball-version
-
-
## Helpers: Valgrind runner
if USE_VALGRIND
diff --git a/build-aux/git-version-gen b/build-aux/git-version-gen
deleted file mode 100755
index 3468247..0000000
--- a/build-aux/git-version-gen
+++ /dev/null
@@ -1,225 +0,0 @@
-#!/bin/sh
-# Print a version string.
-scriptversion=2012-12-31.23; # UTC
-
-# Copyright (C) 2007-2013 Free Software Foundation, Inc.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-
-# This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/.
-# It may be run two ways:
-# - from a git repository in which the "git describe" command below
-# produces useful output (thus requiring at least one signed tag)
-# - from a non-git-repo directory containing a .tarball-version file, which
-# presumes this script is invoked like "./git-version-gen .tarball-version".
-
-# In order to use intra-version strings in your project, you will need two
-# separate generated version string files:
-#
-# .tarball-version - present only in a distribution tarball, and not in
-# a checked-out repository. Created with contents that were learned at
-# the last time autoconf was run, and used by git-version-gen. Must not
-# be present in either $(srcdir) or $(builddir) for git-version-gen to
-# give accurate answers during normal development with a checked out tree,
-# but must be present in a tarball when there is no version control system.
-# Therefore, it cannot be used in any dependencies. GNUmakefile has
-# hooks to force a reconfigure at distribution time to get the value
-# correct, without penalizing normal development with extra reconfigures.
-#
-# .version - present in a checked-out repository and in a distribution
-# tarball. Usable in dependencies, particularly for files that don't
-# want to depend on config.h but do want to track version changes.
-# Delete this file prior to any autoconf run where you want to rebuild
-# files to pick up a version string change; and leave it stale to
-# minimize rebuild time after unrelated changes to configure sources.
-#
-# As with any generated file in a VC'd directory, you should add
-# /.version to .gitignore, so that you don't accidentally commit it.
-# .tarball-version is never generated in a VC'd directory, so needn't
-# be listed there.
-#
-# Use the following line in your configure.ac, so that $(VERSION) will
-# automatically be up-to-date each time configure is run (and note that
-# since configure.ac no longer includes a version string, Makefile rules
-# should not depend on configure.ac for version updates).
-#
-# AC_INIT([GNU project],
-# m4_esyscmd([build-aux/git-version-gen .tarball-version]),
-# [bug-project@example])
-#
-# Then use the following lines in your Makefile.am, so that .version
-# will be present for dependencies, and so that .version and
-# .tarball-version will exist in distribution tarballs.
-#
-# EXTRA_DIST = $(top_srcdir)/.version
-# BUILT_SOURCES = $(top_srcdir)/.version
-# $(top_srcdir)/.version:
-# echo $(VERSION) > $@-t && mv $@-t $@
-# dist-hook:
-# echo $(VERSION) > $(distdir)/.tarball-version
-
-
-me=$0
-
-version="git-version-gen $scriptversion
-
-Copyright 2011 Free Software Foundation, Inc.
-There is NO warranty. You may redistribute this software
-under the terms of the GNU General Public License.
-For more information about these matters, see the files named COPYING."
-
-usage="\
-Usage: $me [OPTION]... \$srcdir/.tarball-version [TAG-NORMALIZATION-SED-SCRIPT]
-Print a version string.
-
-Options:
-
- --prefix prefix of git tags (default 'v')
- --fallback fallback version to use if \"git --version\" fails
-
- --help display this help and exit
- --version output version information and exit
-
-Running without arguments will suffice in most cases."
-
-prefix=v
-fallback=
-
-while test $# -gt 0; do
- case $1 in
- --help) echo "$usage"; exit 0;;
- --version) echo "$version"; exit 0;;
- --prefix) shift; prefix="$1";;
- --fallback) shift; fallback="$1";;
- -*)
- echo "$0: Unknown option '$1'." >&2
- echo "$0: Try '--help' for more information." >&2
- exit 1;;
- *)
- if test "x$tarball_version_file" = x; then
- tarball_version_file="$1"
- elif test "x$tag_sed_script" = x; then
- tag_sed_script="$1"
- else
- echo "$0: extra non-option argument '$1'." >&2
- exit 1
- fi;;
- esac
- shift
-done
-
-if test "x$tarball_version_file" = x; then
- echo "$usage"
- exit 1
-fi
-
-tag_sed_script="${tag_sed_script:-s/x/x/}"
-
-nl='
-'
-
-# Avoid meddling by environment variable of the same name.
-v=
-v_from_git=
-
-# First see if there is a tarball-only version file.
-# then try "git describe", then default.
-if test -f $tarball_version_file
-then
- v=`cat $tarball_version_file` || v=
- case $v in
- *$nl*) v= ;; # reject multi-line output
- [0-9]*) ;;
- *) v= ;;
- esac
- test "x$v" = x \
- && echo "$0: WARNING: $tarball_version_file is missing or damaged" 1>&2
-fi
-
-if test "x$v" != x
-then
- : # use $v
-# Otherwise, if there is at least one git commit involving the working
-# directory, and "git describe" output looks sensible, use that to
-# derive a version string.
-elif test "`git log -1 --pretty=format:x . 2>&1`" = x \
- && v=`git describe --abbrev=4 --match="$prefix*" HEAD 2>/dev/null \
- || git describe --abbrev=4 HEAD 2>/dev/null` \
- && v=`printf '%s\n' "$v" | sed "$tag_sed_script"` \
- && case $v in
- $prefix[0-9]*) ;;
- *) (exit 1) ;;
- esac
-then
- # Is this a new git that lists number of commits since the last
- # tag or the previous older version that did not?
- # Newer: v6.10-77-g0f8faeb
- # Older: v6.10-g0f8faeb
- case $v in
- *-*-*) : git describe is okay three part flavor ;;
- *-*)
- : git describe is older two part flavor
- # Recreate the number of commits and rewrite such that the
- # result is the same as if we were using the newer version
- # of git describe.
- vtag=`echo "$v" | sed 's/-.*//'`
- commit_list=`git rev-list "$vtag"..HEAD 2>/dev/null` \
- || { commit_list=failed;
- echo "$0: WARNING: git rev-list failed" 1>&2; }
- numcommits=`echo "$commit_list" | wc -l`
- v=`echo "$v" | sed "s/\(.*\)-\(.*\)/\1-$numcommits-\2/"`;
- test "$commit_list" = failed && v=UNKNOWN
- ;;
- esac
-
- # Change the first '-' to a '.', so version-comparing tools work properly.
- # Remove the "g" in git describe's output string, to save a byte.
- v=`echo "$v" | sed 's/-/./;s/\(.*\)-g/\1-/'`;
- v_from_git=1
-elif test "x$fallback" = x || git --version >/dev/null 2>&1; then
- v=UNKNOWN
-else
- v=$fallback
-fi
-
-v=`echo "$v" |sed "s/^$prefix//"`
-
-# Test whether to append the "-dirty" suffix only if the version
-# string we're using came from git. I.e., skip the test if it's "UNKNOWN"
-# or if it came from .tarball-version.
-if test "x$v_from_git" != x; then
- # Don't declare a version "dirty" merely because a time stamp has changed.
- git update-index --refresh > /dev/null 2>&1
-
- dirty=`exec 2>/dev/null;git diff-index --name-only HEAD` || dirty=
- case "$dirty" in
- '') ;;
- *) # Append the suffix only if there isn't one already.
- case $v in
- *-dirty) ;;
- *) v="$v-dirty" ;;
- esac ;;
- esac
-fi
-
-# Omit the trailing newline, so that m4_esyscmd can use the result directly.
-echo "$v" | tr -d "$nl"
-
-# Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "scriptversion="
-# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
-# time-stamp-end: "; # UTC"
-# End:
diff --git a/configure.ac b/configure.ac
index f837f1b..e43633d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
AC_PREREQ([2.69])
-AC_INIT([blogc], m4_esyscmd([build-aux/git-version-gen .tarball-version]),
- [https://github.com/blogc/blogc], [blogc], [https://blogc.rgm.io])
+AC_INIT([blogc], [0.6.1], [https://github.com/blogc/blogc], [blogc],
+ [https://blogc.rgm.io])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
--
cgit v1.2.3-18-g5258
From 0400a1a365b67e2bd9acc6fe4e5fb4d1ec2cf825 Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Thu, 14 Jan 2016 22:55:49 +0100
Subject: build: version bump
---
blogc.spec.in | 3 +++
configure.ac | 2 +-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/blogc.spec.in b/blogc.spec.in
index f10e7fc..e185379 100644
--- a/blogc.spec.in
+++ b/blogc.spec.in
@@ -38,6 +38,9 @@ rm -rf $RPM_BUILD_ROOT
%changelog
+* Thu Jan 14 2016 Rafael G. Martins 0.7-1
+- New release.
+
* Sun Jan 10 2016 Rafael G. Martins 0.6.1-1
- New release.
diff --git a/configure.ac b/configure.ac
index e43633d..cd52b20 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
AC_PREREQ([2.69])
-AC_INIT([blogc], [0.6.1], [https://github.com/blogc/blogc], [blogc],
+AC_INIT([blogc], [0.7], [https://github.com/blogc/blogc], [blogc],
[https://blogc.rgm.io])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
--
cgit v1.2.3-18-g5258
From 06d8ca94860f4a795995d811cef477969baa2331 Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Sat, 16 Jan 2016 18:42:05 +0100
Subject: build: spec: do not hardcode package name
---
blogc.spec.in | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/blogc.spec.in b/blogc.spec.in
index e185379..b66d92a 100644
--- a/blogc.spec.in
+++ b/blogc.spec.in
@@ -1,4 +1,4 @@
-Name: blogc
+Name: @PACKAGE_NAME@
Version: @PACKAGE_VERSION@
Release: 1%{?dist}
License: BSD
--
cgit v1.2.3-18-g5258
From cb132cf02e57f57f4507fbc0126481629d83f209 Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Fri, 22 Jan 2016 19:29:57 +0100
Subject: content-parser: encode html entities found in code blocks (fixes #3)
---
src/content-parser.c | 40 ++++++++++++++++++++++++++++++++++++++--
src/content-parser.h | 1 +
tests/check_content_parser.c | 20 ++++++++++++++++----
3 files changed, 55 insertions(+), 6 deletions(-)
diff --git a/src/content-parser.c b/src/content-parser.c
index b22eb70..5b85586 100644
--- a/src/content-parser.c
+++ b/src/content-parser.c
@@ -41,6 +41,40 @@ blogc_slugify(const char *str)
}
+char*
+blogc_htmlentities(const char *str)
+{
+ if (str == NULL)
+ return NULL;
+ b_string_t *rv = b_string_new();
+ for (unsigned int i = 0; str[i] != '\0'; i++) {
+ switch (str[i]) {
+ case '&':
+ b_string_append(rv, "&");
+ break;
+ case '<':
+ b_string_append(rv, "<");
+ break;
+ case '>':
+ b_string_append(rv, ">");
+ break;
+ case '"':
+ b_string_append(rv, """);
+ break;
+ case '\'':
+ b_string_append(rv, "'");
+ break;
+ case '/':
+ b_string_append(rv, "/");
+ break;
+ default:
+ b_string_append_c(rv, str[i]);
+ }
+ }
+ return b_string_free(rv, false);
+}
+
+
typedef enum {
CONTENT_START_LINE = 1,
CONTENT_EXCERPT,
@@ -698,11 +732,13 @@ blogc_content_parse(const char *src, size_t *end_excerpt)
if (c == '\n' || c == '\r' || is_last) {
b_string_append(rv, "");
for (b_slist_t *l = lines; l != NULL; l = l->next) {
+ char *tmp_line = blogc_htmlentities(l->data);
if (l->next == NULL)
- b_string_append_printf(rv, "%s", l->data);
+ b_string_append_printf(rv, "%s", tmp_line);
else
- b_string_append_printf(rv, "%s%s", l->data,
+ b_string_append_printf(rv, "%s%s", tmp_line,
line_ending);
+ free(tmp_line);
}
b_string_append_printf(rv, "
%s", line_ending);
b_slist_free_full(lines, free);
diff --git a/src/content-parser.h b/src/content-parser.h
index 5802594..6617bb4 100644
--- a/src/content-parser.h
+++ b/src/content-parser.h
@@ -13,6 +13,7 @@
#include
char* blogc_slugify(const char *str);
+char* blogc_htmlentities(const char *str);
char* blogc_content_parse_inline(const char *src);
bool blogc_is_ordered_list_item(const char *str, size_t prefix_len);
char* blogc_content_parse(const char *src, size_t *end_excerpt);
diff --git a/tests/check_content_parser.c b/tests/check_content_parser.c
index 8ed9520..970ec5c 100644
--- a/tests/check_content_parser.c
+++ b/tests/check_content_parser.c
@@ -48,6 +48,17 @@ test_slugify(void **state)
}
+static void
+test_htmlentities(void **state)
+{
+ char *s = blogc_htmlentities(NULL);
+ assert_null(s);
+ s = blogc_htmlentities("asdxcv & < > \" 'sfd/gf");
+ assert_string_equal(s, "asdxcv & < > " 'sfd/gf");
+ free(s);
+}
+
+
static void
test_is_ordered_list_item(void **state)
{
@@ -87,7 +98,7 @@ test_content_parse(void **state)
"> \n"
"> asd\n"
"\n"
- " bola\n"
+ " bola\n"
" asd\n"
" qwewer\n"
"\n"
@@ -122,7 +133,7 @@ test_content_parse(void **state)
"buga
\n"
"asd
\n"
"\n"
- "bola\n"
+ "<asd>bola</asd>\n"
" asd\n"
"qwewer
\n"
"
\n"
@@ -165,7 +176,7 @@ test_content_parse_crlf(void **state)
"> \r\n"
"> asd\r\n"
"\r\n"
- " bola\r\n"
+ " bola\r\n"
" asd\r\n"
" qwewer\r\n"
"\r\n"
@@ -200,7 +211,7 @@ test_content_parse_crlf(void **state)
"buga\r\n"
"asd
\r\n"
"\r\n"
- "bola\r\n"
+ "<asd>bola</asd>\r\n"
" asd\r\n"
"qwewer
\r\n"
"
\r\n"
@@ -1663,6 +1674,7 @@ main(void)
{
const UnitTest tests[] = {
unit_test(test_slugify),
+ unit_test(test_htmlentities),
unit_test(test_is_ordered_list_item),
unit_test(test_content_parse),
unit_test(test_content_parse_crlf),
--
cgit v1.2.3-18-g5258
From 254b2f23440cb9360cf2e19906d0b56256412e26 Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Fri, 22 Jan 2016 19:57:24 +0100
Subject: content-parser: use size_t instead of unsigned len when handling
strings
---
src/content-parser.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/content-parser.c b/src/content-parser.c
index 5b85586..1a929e2 100644
--- a/src/content-parser.c
+++ b/src/content-parser.c
@@ -27,7 +27,7 @@ blogc_slugify(const char *str)
return NULL;
char *new_str = b_strdup(str);
int diff = 'a' - 'A'; // just to avoid magic numbers
- for (unsigned int i = 0; new_str[i] != '\0'; i++) {
+ for (size_t i = 0; new_str[i] != '\0'; i++) {
if (new_str[i] >= 'a' && new_str[i] <= 'z')
continue;
if (new_str[i] >= '0' && new_str[i] <= '9')
@@ -47,7 +47,7 @@ blogc_htmlentities(const char *str)
if (str == NULL)
return NULL;
b_string_t *rv = b_string_new();
- for (unsigned int i = 0; str[i] != '\0'; i++) {
+ for (size_t i = 0; str[i] != '\0'; i++) {
switch (str[i]) {
case '&':
b_string_append(rv, "&");
--
cgit v1.2.3-18-g5258
From c7297cb5e74727c136547f588503e488ca40dd30 Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Fri, 22 Jan 2016 20:32:30 +0100
Subject: build: version bump
---
blogc.spec.in | 3 +++
configure.ac | 2 +-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/blogc.spec.in b/blogc.spec.in
index b66d92a..53364f9 100644
--- a/blogc.spec.in
+++ b/blogc.spec.in
@@ -38,6 +38,9 @@ rm -rf $RPM_BUILD_ROOT
%changelog
+* Fri Jan 22 2016 Rafael G. Martins 0.7.1-1
+- New release.
+
* Thu Jan 14 2016 Rafael G. Martins 0.7-1
- New release.
diff --git a/configure.ac b/configure.ac
index cd52b20..4303f97 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
AC_PREREQ([2.69])
-AC_INIT([blogc], [0.7], [https://github.com/blogc/blogc], [blogc],
+AC_INIT([blogc], [0.7.1], [https://github.com/blogc/blogc], [blogc],
[https://blogc.rgm.io])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
--
cgit v1.2.3-18-g5258
From 35c4f119ca188fd9e90a2bbada864f9d121459ba Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Mon, 25 Jan 2016 04:46:19 +0100
Subject: renderer: fix bug when 'if' evals to false after 'if' evals to true
---
src/renderer.c | 10 +++++-----
tests/check_renderer.c | 32 ++++++++++++++++++++++++++++++++
2 files changed, 37 insertions(+), 5 deletions(-)
diff --git a/src/renderer.c b/src/renderer.c
index 0f5d10a..5e07b0c 100644
--- a/src/renderer.c
+++ b/src/renderer.c
@@ -134,7 +134,6 @@ blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config, bool listing
char *defined = NULL;
unsigned int if_count = 0;
- unsigned int if_skip = 0;
b_slist_t *foreach_var = NULL;
b_slist_t *foreach_var_start = NULL;
@@ -237,6 +236,7 @@ blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config, bool listing
case BLOGC_TEMPLATE_IF_STMT:
case BLOGC_TEMPLATE_IFDEF_STMT:
+ if_count = 0;
defined = NULL;
if (stmt->value != NULL)
defined = blogc_format_variable(stmt->value, config,
@@ -283,7 +283,6 @@ blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config, bool listing
evaluate = true;
}
if (!evaluate) {
- if_skip = if_count;
// at this point we can just skip anything, counting the
// number of 'if's, to know how many 'endif's we need to
@@ -299,11 +298,11 @@ blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config, bool listing
continue;
}
if (stmt->type == BLOGC_TEMPLATE_ENDIF_STMT) {
- if (if_count > if_skip) {
+ if (if_count > 0) {
if_count--;
continue;
}
- if (if_count == if_skip)
+ if (if_count == 0)
break;
}
}
@@ -314,7 +313,8 @@ blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config, bool listing
break;
case BLOGC_TEMPLATE_ENDIF_STMT:
- if_count--;
+ if (if_count > 0)
+ if_count--;
break;
case BLOGC_TEMPLATE_FOREACH_STMT:
diff --git a/tests/check_renderer.c b/tests/check_renderer.c
index 360f067..d6bc947 100644
--- a/tests/check_renderer.c
+++ b/tests/check_renderer.c
@@ -686,6 +686,37 @@ test_render_respect_variable_scope(void **state)
}
+static void
+test_render_ifcount_bug(void **state)
+{
+ const char *str =
+ "{% block entry %}\n"
+ "{% ifdef TITLE %}{{ TITLE }}
{% endif %}\n"
+ "{% ifdef IS_POST %}\n"
+ "{% ifdef ASD %}ASD{% 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 = NULL;
+ s = b_slist_append(s, b_trie_new(free));
+ b_trie_insert(s->data, "TITLE", b_strdup("bola"));
+ b_trie_t *c = b_trie_new(free);
+ char *out = blogc_render(l, s, c, false);
+ assert_string_equal(out,
+ "\n"
+ "bola
\n"
+ "\n"
+ "\n");
+ b_trie_free(c);
+ blogc_template_free_stmts(l);
+ b_slist_free_full(s, (b_free_func_t) b_trie_free);
+ free(out);
+}
+
+
static void
test_get_variable(void **state)
{
@@ -897,6 +928,7 @@ main(void)
unit_test(test_render_outside_block),
unit_test(test_render_prefer_local_variable),
unit_test(test_render_respect_variable_scope),
+ unit_test(test_render_ifcount_bug),
unit_test(test_get_variable),
unit_test(test_get_variable_only_local),
unit_test(test_get_variable_only_global),
--
cgit v1.2.3-18-g5258
From 3b0ea0a4908f1702308354ec7cbd8db5c80f87ee Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins"
Date: Mon, 25 Jan 2016 20:07:57 +0100
Subject: build: version bump
---
blogc.spec.in | 3 +++
configure.ac | 2 +-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/blogc.spec.in b/blogc.spec.in
index 53364f9..3fa3353 100644
--- a/blogc.spec.in
+++ b/blogc.spec.in
@@ -38,6 +38,9 @@ rm -rf $RPM_BUILD_ROOT
%changelog
+* Mon Jan 25 2016 Rafael G. Martins 0.7.2-1
+- New release.
+
* Fri Jan 22 2016 Rafael G. Martins 0.7.1-1
- New release.
diff --git a/configure.ac b/configure.ac
index 4303f97..9ceed22 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
AC_PREREQ([2.69])
-AC_INIT([blogc], [0.7.1], [https://github.com/blogc/blogc], [blogc],
+AC_INIT([blogc], [0.7.2], [https://github.com/blogc/blogc], [blogc],
[https://blogc.rgm.io])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
--
cgit v1.2.3-18-g5258