aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael G. Martins <rafael@rafaelmartins.eng.br>2023-02-11 22:45:04 +0100
committerRafael G. Martins <rafael@rafaelmartins.eng.br>2023-02-11 22:45:04 +0100
commite52e1f0b9d0796412ee36de260c6bbbcde348b0a (patch)
tree10ddf0388f652b3504d82bbc80c62081edf2cf09
parent2435cfdb859cfed420e963e098ae3e2260be79f9 (diff)
downloadblogc-e52e1f0b9d0796412ee36de260c6bbbcde348b0a.tar.gz
blogc-e52e1f0b9d0796412ee36de260c6bbbcde348b0a.tar.bz2
blogc-e52e1f0b9d0796412ee36de260c6bbbcde348b0a.zip
blogc: renderer: add `FOREACH_VALUE` variable
-rw-r--r--man/blogc-template.7.ronn34
-rw-r--r--src/blogc/main.c2
-rw-r--r--src/blogc/renderer.c58
-rw-r--r--src/blogc/renderer.h2
-rw-r--r--tests/blogc/check_renderer.c60
5 files changed, 127 insertions, 29 deletions
diff --git a/man/blogc-template.7.ronn b/man/blogc-template.7.ronn
index 5184941..1530fb3 100644
--- a/man/blogc-template.7.ronn
+++ b/man/blogc-template.7.ronn
@@ -317,16 +317,40 @@ This is how a `foreach` iterator is defined in a template:
{% endforeach %}
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.
+is the variable defined by blogc(1), that will store the item for a given iteration.
If the value of the `TAGS` variable is "item1 item2 item3", this template is
-rendered 3 times, one for each item value.
+rendered 3 times, one for each item.
-The `FOREACH_ITEM` variable can be truncated, like:
+It is possible to map the items to arbitrary strings by defining other variables
+following a predefined for naming schema, like:
+
+ TAGS__ITEM1
+
+Where `TAGS` is the variable defined in the foreach iterator, and `ITEM1` is the
+current iteration item (the value of `FOREACH_ITEM` for the current iteration,
+converted to upper case and with special characters converted to `_`).
+
+This is how a `foreach` iterator using arbitrary string mapping is defined in a template:
+
+ {% foreach TAGS %}
+ <a href="/tag/{{ FOREACH_ITEM }}/">{{ FOREACH_VALUE }}</a>
+ {% endforeach %}
+
+`FOREACH_VALUE` is the variable defined by blogc(1), that will store the arbitrary string
+mapped to current iteration item. This variable can be checked using `ifdef` conditionals
+(and similar) as usual:
+
+ {% foreach TAGS %}
+ {% ifdef FOREACH_VALUE %}
+ <a href="/tag/{{ FOREACH_ITEM }}/">{{ FOREACH_VALUE }}</a>
+ {% endif %}
+ {% endforeach %}
+
+The `FOREACH_ITEM` and `FOREACH_VALUE` variables can be truncated, like:
{% foreach TAGS %}
- <a href="/tag/{{ FOREACH_ITEM }}/">{{ FOREACH_ITEM_5 }}</a>
+ <a href="/tag/{{ FOREACH_ITEM_5 }}/">{{ FOREACH_VALUE_5 }}</a>
{% endforeach %}
## WHITESPACE CONTROL
diff --git a/src/blogc/main.c b/src/blogc/main.c
index 7024967..9bfa9cf 100644
--- a/src/blogc/main.c
+++ b/src/blogc/main.c
@@ -322,7 +322,7 @@ main(int argc, char **argv)
if (!listing && s != NULL) {
local = s->data;
}
- char *val = blogc_format_variable(print, config, local, NULL);
+ char *val = blogc_format_variable(print, config, local, NULL, NULL);
if (val == NULL) {
fprintf(stderr, "blogc: error: variable not found: %s\n",
print);
diff --git a/src/blogc/renderer.c b/src/blogc/renderer.c
index 785c77b..a91d105 100644
--- a/src/blogc/renderer.c
+++ b/src/blogc/renderer.c
@@ -54,22 +54,57 @@ blogc_format_date(const char *date, bc_trie_t *global, bc_trie_t *local)
}
+static char*
+foreach_value_variable(const char *name, const char *item)
+{
+ if (name == NULL || item == NULL)
+ return NULL;
+
+ char *rv = bc_strdup_printf("%s__%s", name, item);
+ int diff = 'a' - 'A'; // just to avoid magic numbers
+ for (size_t i = 0; rv[i] != '\0'; i++) {
+ if ((rv[i] >= '0' && rv[i] <= '9') ||
+ (rv[i] >= 'A' && rv[i] <= 'Z')) {
+ continue;
+ }
+ if (rv[i] >= 'a' && rv[i] <= 'z') {
+ rv[i] -= diff;
+ continue;
+ }
+ rv[i] = '_';
+ }
+
+ return rv;
+}
+
+
char*
blogc_format_variable(const char *name, bc_trie_t *global, bc_trie_t *local,
- bc_slist_t *foreach_var)
+ const char *foreach_name, bc_slist_t *foreach_var)
{
// if used asked for a variable that exists, just return it right away
const char *value = blogc_get_variable(name, global, local);
if (value != NULL)
return bc_strdup(value);
- // do the same for special variable 'FOREACH_ITEM'
+ // do the same for special foreach variables
if (0 == strcmp(name, "FOREACH_ITEM")) {
if (foreach_var != NULL && foreach_var->data != NULL) {
return bc_strdup(foreach_var->data);
}
return NULL;
}
+ if (0 == strcmp(name, "FOREACH_VALUE")) {
+ if (foreach_name != NULL && foreach_var != NULL && foreach_var->data != NULL) {
+ char *value_var = foreach_value_variable(foreach_name, foreach_var->data);
+ if (value_var != NULL) {
+ value = blogc_get_variable(value_var, global, local);
+ free(value_var);
+ return bc_strdup(value);
+ }
+ }
+ return NULL;
+ }
char *var = bc_strdup(name);
@@ -105,6 +140,14 @@ blogc_format_variable(const char *name, bc_trie_t *global, bc_trie_t *local,
(foreach_var != NULL && foreach_var->data != NULL)) {
value = foreach_var->data;
}
+ else if ((0 == strcmp(var, "FOREACH_VALUE")) &&
+ (foreach_name != NULL && foreach_var != NULL && foreach_var->data != NULL)) {
+ char *value_var = foreach_value_variable(foreach_name, foreach_var->data);
+ if (value_var != NULL) {
+ value = blogc_get_variable(value_var, global, local);
+ free(value_var);
+ }
+ }
else {
blogc_funcvars_eval(global, var);
value = blogc_get_variable(var, global, local);
@@ -183,6 +226,7 @@ blogc_render(bc_slist_t *tmpl, bc_slist_t *sources, bc_slist_t *listing_entries,
size_t if_count = 0;
+ char *foreach_name = NULL;
bc_slist_t *foreach_var = NULL;
bc_slist_t *foreach_var_start = NULL;
bc_slist_t *foreach_start = NULL;
@@ -289,7 +333,7 @@ blogc_render(bc_slist_t *tmpl, bc_slist_t *sources, bc_slist_t *listing_entries,
case BLOGC_TEMPLATE_NODE_VARIABLE:
if (node->data[0] != NULL) {
config_value = blogc_format_variable(node->data[0],
- config, inside_block ? tmp_source : NULL, foreach_var);
+ config, inside_block ? tmp_source : NULL, foreach_name, foreach_var);
if (config_value != NULL) {
bc_string_append(str, config_value);
free(config_value);
@@ -321,7 +365,7 @@ blogc_render(bc_slist_t *tmpl, bc_slist_t *sources, bc_slist_t *listing_entries,
defined = NULL;
if (node->data[0] != NULL)
defined = blogc_format_variable(node->data[0], config,
- inside_block ? tmp_source : NULL, foreach_var);
+ inside_block ? tmp_source : NULL, foreach_name, foreach_var);
evaluate = false;
if (node->op != 0) {
// Strings that start with a '"' are actually strings, the
@@ -339,7 +383,7 @@ blogc_render(bc_slist_t *tmpl, bc_slist_t *sources, bc_slist_t *listing_entries,
else {
defined2 = blogc_format_variable(node->data[1],
config, inside_block ? tmp_source : NULL,
- foreach_var);
+ foreach_name, foreach_var);
}
}
@@ -452,6 +496,7 @@ blogc_render(bc_slist_t *tmpl, bc_slist_t *sources, bc_slist_t *listing_entries,
config, inside_block ? tmp_source : NULL);
if (foreach_var_start != NULL) {
+ foreach_name = bc_strdup(node->data[0]);
foreach_var = foreach_var_start;
foreach_start = tmp;
}
@@ -469,6 +514,7 @@ blogc_render(bc_slist_t *tmpl, bc_slist_t *sources, bc_slist_t *listing_entries,
if (foreach_var == NULL) {
foreach_start = tmp;
+ foreach_name = bc_strdup(node->data[0]);
foreach_var = foreach_var_start;
}
break;
@@ -484,6 +530,8 @@ blogc_render(bc_slist_t *tmpl, bc_slist_t *sources, bc_slist_t *listing_entries,
foreach_start = NULL;
bc_slist_free_full(foreach_var_start, free);
foreach_var_start = NULL;
+ free(foreach_name);
+ foreach_name = NULL;
break;
}
tmp = tmp->next;
diff --git a/src/blogc/renderer.h b/src/blogc/renderer.h
index 77f20f5..77c660a 100644
--- a/src/blogc/renderer.h
+++ b/src/blogc/renderer.h
@@ -15,7 +15,7 @@
const char* blogc_get_variable(const char *name, bc_trie_t *global, bc_trie_t *local);
char* blogc_format_date(const char *date, bc_trie_t *global, bc_trie_t *local);
char* blogc_format_variable(const char *name, bc_trie_t *global, bc_trie_t *local,
- bc_slist_t *foreach_var);
+ const char *foreach_name, bc_slist_t *foreach_var);
bc_slist_t* blogc_split_list_variable(const char *name, bc_trie_t *global,
bc_trie_t *local);
char* blogc_render(bc_slist_t *tmpl, bc_slist_t *sources, bc_slist_t *listing_entries,
diff --git a/tests/blogc/check_renderer.c b/tests/blogc/check_renderer.c
index a5d6729..08aed84 100644
--- a/tests/blogc/check_renderer.c
+++ b/tests/blogc/check_renderer.c
@@ -1253,23 +1253,23 @@ test_format_variable(void **state)
bc_trie_insert(l, "NAME", bc_strdup("chunda"));
bc_trie_insert(l, "TITLE", bc_strdup("chunda2"));
bc_trie_insert(l, "SIZE", bc_strdup("1234567890987654321"));
- char *tmp = blogc_format_variable("NAME", g, l, NULL);
+ char *tmp = blogc_format_variable("NAME", g, l, NULL, NULL);
assert_string_equal(tmp, "chunda");
free(tmp);
- tmp = blogc_format_variable("TITLE", g, l, NULL);
+ tmp = blogc_format_variable("TITLE", g, l, NULL, NULL);
assert_string_equal(tmp, "chunda2");
free(tmp);
- tmp = blogc_format_variable("TITLE_2", g, l, NULL);
+ tmp = blogc_format_variable("TITLE_2", g, l, NULL, NULL);
assert_string_equal(tmp, "ch");
free(tmp);
- tmp = blogc_format_variable("SIZE_12", g, l, NULL);
+ tmp = blogc_format_variable("SIZE_12", g, l, NULL, NULL);
assert_string_equal(tmp, "123456789098");
free(tmp);
- tmp = blogc_format_variable("SIZE_200", g, l, NULL);
+ tmp = blogc_format_variable("SIZE_200", g, l, NULL, NULL);
assert_string_equal(tmp, "1234567890987654321");
free(tmp);
- assert_null(blogc_format_variable("SIZE_", g, l, NULL));
- assert_null(blogc_format_variable("BOLA", g, l, NULL));
+ assert_null(blogc_format_variable("SIZE_", g, l, NULL, NULL));
+ assert_null(blogc_format_variable("BOLA", g, l, NULL, NULL));
bc_trie_free(g);
bc_trie_free(l);
}
@@ -1283,13 +1283,13 @@ test_format_variable_with_date(void **state)
bc_trie_insert(g, "DATE_FORMAT", bc_strdup("%R"));
bc_trie_t *l = bc_trie_new(free);
bc_trie_insert(l, "DATE", bc_strdup("2011-12-13 14:15:16"));
- char *tmp = blogc_format_variable("DATE_FORMATTED", g, l, NULL);
+ char *tmp = blogc_format_variable("DATE_FORMATTED", g, l, NULL, NULL);
assert_string_equal(tmp, "14:15");
free(tmp);
- tmp = blogc_format_variable("DATE_FORMATTED_3", g, l, NULL);
+ tmp = blogc_format_variable("DATE_FORMATTED_3", g, l, NULL, NULL);
assert_string_equal(tmp, "14:");
free(tmp);
- tmp = blogc_format_variable("DATE_FORMATTED_10", g, l, NULL);
+ tmp = blogc_format_variable("DATE_FORMATTED_10", g, l, NULL, NULL);
assert_string_equal(tmp, "14:15");
free(tmp);
bc_trie_free(g);
@@ -1304,15 +1304,13 @@ test_format_variable_foreach(void **state)
l = bc_slist_append(l, bc_strdup("asd"));
l = bc_slist_append(l, bc_strdup("qwe"));
l = bc_slist_append(l, bc_strdup("zxcvbn"));
- char *tmp = blogc_format_variable("FOREACH_ITEM", NULL, NULL, l->next);
+ char *tmp = blogc_format_variable("FOREACH_ITEM", NULL, NULL, NULL, l->next);
assert_string_equal(tmp, "qwe");
free(tmp);
- tmp = blogc_format_variable("FOREACH_ITEM_4", NULL, NULL,
- l->next->next);
+ tmp = blogc_format_variable("FOREACH_ITEM_4", NULL, NULL, NULL, l->next->next);
assert_string_equal(tmp, "zxcv");
free(tmp);
- tmp = blogc_format_variable("FOREACH_ITEM_10", NULL, NULL,
- l->next->next);
+ tmp = blogc_format_variable("FOREACH_ITEM_10", NULL, NULL, NULL, l->next->next);
assert_string_equal(tmp, "zxcvbn");
free(tmp);
bc_slist_free_full(l, free);
@@ -1320,10 +1318,37 @@ test_format_variable_foreach(void **state)
static void
+test_format_variable_foreach_value(void **state)
+{
+ bc_trie_t *gl = bc_trie_new(free);
+ bc_trie_insert(gl, "FOO_BAR__QWE", bc_strdup("bnm"));
+ bc_trie_t *loc = bc_trie_new(free);
+ bc_trie_insert(loc, "BAR__ZXCVBN", bc_strdup("dfg"));
+ bc_trie_insert(loc, "HUE__ZXCVBN", bc_strdup("xcv"));
+ bc_slist_t *l = NULL;
+ l = bc_slist_append(l, bc_strdup("asd"));
+ l = bc_slist_append(l, bc_strdup("qwe"));
+ l = bc_slist_append(l, bc_strdup("zxcvbn"));
+ char *tmp = blogc_format_variable("FOREACH_VALUE", gl, loc, "foo-bar", l->next);
+ assert_string_equal(tmp, "bnm");
+ free(tmp);
+ tmp = blogc_format_variable("FOREACH_VALUE_2", gl, loc, "bar", l->next->next);
+ assert_string_equal(tmp, "df");
+ free(tmp);
+ tmp = blogc_format_variable("FOREACH_VALUE_4", gl, loc, "hue", l->next->next);
+ assert_string_equal(tmp, "xcv");
+ free(tmp);
+ bc_trie_free(gl);
+ bc_trie_free(loc);
+ bc_slist_free_full(l, free);
+}
+
+
+static void
test_format_variable_foreach_empty(void **state)
{
- assert_null(blogc_format_variable("FOREACH_ITEM", NULL, NULL, NULL));
- assert_null(blogc_format_variable("FOREACH_ITEM_4", NULL, NULL, NULL));
+ assert_null(blogc_format_variable("FOREACH_ITEM", NULL, NULL, NULL, NULL));
+ assert_null(blogc_format_variable("FOREACH_ITEM_4", NULL, NULL, NULL, NULL));
}
@@ -1401,6 +1426,7 @@ main(void)
cmocka_unit_test(test_format_variable),
cmocka_unit_test(test_format_variable_with_date),
cmocka_unit_test(test_format_variable_foreach),
+ cmocka_unit_test(test_format_variable_foreach_value),
cmocka_unit_test(test_format_variable_foreach_empty),
cmocka_unit_test(test_split_list_variable),
cmocka_unit_test(test_split_list_variable_not_found),