From fabdcfe3f7dc890f89c0ca2f0ef034d189226531 Mon Sep 17 00:00:00 2001 From: "Rafael G. Martins" Date: Sun, 29 May 2016 14:19:54 +0200 Subject: renderer: added support to truncate variables. this commit also documents variable formatters properly. --- man/blogc-source.7.ronn | 4 ++- man/blogc-template.7.ronn | 36 +++++++++++++++++++++++++++ src/renderer.c | 62 +++++++++++++++++++++++++++++++++++++++++------ tests/check_renderer.c | 28 +++++++++++++++++++++ 4 files changed, 121 insertions(+), 9 deletions(-) diff --git a/man/blogc-source.7.ronn b/man/blogc-source.7.ronn index 9a0c94c..5bb3b32 100644 --- a/man/blogc-source.7.ronn +++ b/man/blogc-source.7.ronn @@ -55,7 +55,9 @@ parser. It contains the unparsed content of the first paragraph found in the source file. The content is not parsed but HTML entities are encoded. Paragraphs inside blockquotes are ignored. This variable can be overriden by an explicit definition in source file, that must have the HTML entities escaped manually. -This is useful to add "description" meta-tags to HTML templates. +This is useful to add "description" meta-tags to HTML templates. It may be +needed to truncate the variable size to an maximum length, take a look at +blogc-template(7). ## SOURCE CONTENT - BLOCK ELEMENTS diff --git a/man/blogc-template.7.ronn b/man/blogc-template.7.ronn index bd38618..3499d7c 100644 --- a/man/blogc-template.7.ronn +++ b/man/blogc-template.7.ronn @@ -105,6 +105,36 @@ won't raise any error in this case. Variables are always strings, even if the value of the variable is a number, it is handled as a string by blogc(1). +### Variable formatters + +blogc(1) can apply a formatter to a variable, depending on how it is called +in the template. If user append `_FORMATTED` to the end of the variable name, +a formatter will be applied, if available for the variable name: + +- Date formatter: if variable name starts with `DATE_`, it is formatted with + a strptime(3) format, provided by `DATE_FORMAT` variable. The `DATE_FORMATTED` + "meta-variable" will return the formatted version of the `DATE` variable. + If `DATE_FORMAT` is not provided, the original value will be returned. + +An existing variable is not overrided by formatter. That means that if +`FOO_FORMATTED` variable exists, it won't be handled as a formatter +"meta-variable", and `FOO_FORMATTED` variable value will be returned normally. + +### Truncated variables + +blogc(1) can truncate the value of a variable to a maximum length, if it is +called with the maximum length appended to the end of the variable, like: +`FOO_5` will return the 5 first characters of the `FOO` variable, if bigger +than 5 characters. + +This is applicable to the "meta-variables", like `DATE_FORMATTED`. It can +be truncated like: `DATE_FORMATTED_5`, that will return the 5 first +characters of the `DATE_FORMATTED` "meta-variable". + +An existing variable is not overrided by the truncate syntax. That means +that if `FOO_5` variable exists, it won't be handled as a truncate +"meta-variable", and `FOO_5` variable value will be returned normally. + ## TEMPLATE CONDITIONALS Template conditionals are used to include content to the output, or not, @@ -199,6 +229,12 @@ iteration. If the value of the `TAGS` variable is "item1 item2 item3", this template is rendered 3 times, one for each item value. +The `FOREACH_ITEM` variable can be truncated, like: + + {% foreach TAGS %} + {{ FOREACH_ITEM_5 }} + {% endforeach %} + ## WHITESPACE CONTROL Users can control how whitespaces (space, form-feed (`\f`), newline (`\n`), diff --git a/src/renderer.c b/src/renderer.c index 5af3b8a..0f71ba7 100644 --- a/src/renderer.c +++ b/src/renderer.c @@ -10,6 +10,7 @@ #include #endif /* HAVE_CONFIG_H */ +#include #include #include #include @@ -61,6 +62,12 @@ char* blogc_format_variable(const char *name, sb_trie_t *global, sb_trie_t *local, sb_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 sb_strdup(value); + + // do the same for special variable 'FOREACH_ITEM' if (0 == strcmp(name, "FOREACH_ITEM")) { if (foreach_var != NULL && foreach_var->data != NULL) { return sb_strdup(foreach_var->data); @@ -68,30 +75,69 @@ blogc_format_variable(const char *name, sb_trie_t *global, sb_trie_t *local, return NULL; } - char *var = NULL; + char *var = sb_strdup(name); + + size_t i; + size_t last = strlen(var); + + long int len = -1; + + // just walk till the last '_' + for (i = last - 1; i > 0 && var[i] >= '0' && var[i] <= '9'; i--); + + if (var[i] == '_' && (i + 1) < last) { // var ends with '_[0-9]+' + // passing NULL to endptr because our string was previously validated + len = strtol(var + i + 1, NULL, 10); + if (errno != 0) { + fprintf(stderr, "warning: invalid variable size for '%s' (%s), " + "ignoring.\n", var, strerror(errno)); + len = -1; + } + else { + var[i] = '\0'; + } + } + bool must_format = false; - if (sb_str_ends_with(name, "_FORMATTED")) { - var = sb_strndup(name, strlen(name) - 10); + + if (sb_str_ends_with(var, "_FORMATTED")) { + var[strlen(var) - 10] = '\0'; must_format = true; } - if (var == NULL) - var = sb_strdup(name); - const char *value = blogc_get_variable(var, global, local); + if ((0 == strcmp(var, "FOREACH_ITEM")) && + (foreach_var != NULL && foreach_var->data != NULL)) + value = foreach_var->data; + else + value = blogc_get_variable(var, global, local); + free(var); if (value == NULL) return NULL; char *rv = NULL; + if (must_format) { if (sb_str_starts_with(name, "DATE_")) { rv = blogc_format_date(value, global, local); } + else { + fprintf(stderr, "warning: no formatter found for '%s', " + "ignoring.\n", var); + rv = sb_strdup(value); + } + } + else { + rv = sb_strdup(value); + } + + if (len > 0) { + char *tmp = sb_strndup(rv, len); + free(rv); + rv = tmp; } - if (rv == NULL) - return sb_strdup(value); return rv; } diff --git a/tests/check_renderer.c b/tests/check_renderer.c index 13e7309..0f17d23 100644 --- a/tests/check_renderer.c +++ b/tests/check_renderer.c @@ -820,18 +820,30 @@ test_format_date_without_date(void **state) static void test_format_variable(void **state) { + // FIXME: test warnings sb_trie_t *g = sb_trie_new(free); sb_trie_insert(g, "NAME", sb_strdup("bola")); sb_trie_insert(g, "TITLE", sb_strdup("bola2")); sb_trie_t *l = sb_trie_new(free); sb_trie_insert(l, "NAME", sb_strdup("chunda")); sb_trie_insert(l, "TITLE", sb_strdup("chunda2")); + sb_trie_insert(l, "SIZE", sb_strdup("1234567890987654321")); char *tmp = blogc_format_variable("NAME", g, l, NULL); assert_string_equal(tmp, "chunda"); free(tmp); tmp = blogc_format_variable("TITLE", g, l, NULL); assert_string_equal(tmp, "chunda2"); free(tmp); + tmp = blogc_format_variable("TITLE_2", g, l, NULL); + assert_string_equal(tmp, "ch"); + free(tmp); + tmp = blogc_format_variable("SIZE_12", g, l, NULL); + assert_string_equal(tmp, "123456789098"); + free(tmp); + tmp = blogc_format_variable("SIZE_200", g, l, 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)); sb_trie_free(g); sb_trie_free(l); @@ -849,6 +861,12 @@ test_format_variable_with_date(void **state) char *tmp = blogc_format_variable("DATE_FORMATTED", g, l, NULL); assert_string_equal(tmp, "14:15"); free(tmp); + tmp = blogc_format_variable("DATE_FORMATTED_3", g, l, NULL); + assert_string_equal(tmp, "14:"); + free(tmp); + tmp = blogc_format_variable("DATE_FORMATTED_10", g, l, NULL); + assert_string_equal(tmp, "14:15"); + free(tmp); sb_trie_free(g); sb_trie_free(l); } @@ -860,9 +878,18 @@ test_format_variable_foreach(void **state) sb_slist_t *l = NULL; l = sb_slist_append(l, sb_strdup("asd")); l = sb_slist_append(l, sb_strdup("qwe")); + l = sb_slist_append(l, sb_strdup("zxcvbn")); char *tmp = blogc_format_variable("FOREACH_ITEM", NULL, NULL, l->next); assert_string_equal(tmp, "qwe"); free(tmp); + tmp = blogc_format_variable("FOREACH_ITEM_4", NULL, NULL, + l->next->next); + assert_string_equal(tmp, "zxcv"); + free(tmp); + tmp = blogc_format_variable("FOREACH_ITEM_10", NULL, NULL, + l->next->next); + assert_string_equal(tmp, "zxcvbn"); + free(tmp); sb_slist_free_full(l, free); } @@ -871,6 +898,7 @@ 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)); } -- cgit v1.2.3-18-g5258