diff options
author | Rafael G. Martins <rafael@rafaelmartins.eng.br> | 2015-04-28 02:31:40 -0300 |
---|---|---|
committer | Rafael G. Martins <rafael@rafaelmartins.eng.br> | 2015-04-28 02:31:40 -0300 |
commit | 582cbc6cf67919ec189098817ab1e4541c8e761d (patch) | |
tree | dd045a9d6ba2a2a59ef161774988f0aedcc5c0cb | |
parent | 5205db347cb9f56187c2ad5e767281a7a4016533 (diff) | |
download | blogc-582cbc6cf67919ec189098817ab1e4541c8e761d.tar.gz blogc-582cbc6cf67919ec189098817ab1e4541c8e761d.tar.bz2 blogc-582cbc6cf67919ec189098817ab1e4541c8e761d.zip |
implemented datetime parsing/formatting
-rw-r--r-- | README.md | 6 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | src/main.c | 8 | ||||
-rw-r--r-- | src/renderer.c | 91 | ||||
-rw-r--r-- | src/renderer.h | 2 | ||||
-rw-r--r-- | tests/check_renderer.c | 121 |
6 files changed, 208 insertions, 24 deletions
@@ -50,6 +50,8 @@ If more than one source file is provided to the compiler with the ``-t`` argumen Variables are single-line, and all the whitespace characters, including tabs, before the leading non-whitespace character and after the trailing non-whitespace character will be removed. +``DATE`` variable, if provided in the correct format, as shown in the example, will be parsed and set to ``DATE_FORMATTED`` variable. User can set ``DATE_FORMAT`` variable with ``strftime(3)`` format string, to change the default formatting, e.g. using the -D command line argument: ``-D DATE_FORMAT="%H:%M:%S"`` + Raw content is available in template blocks as the ``CONTENT`` variable. @@ -69,11 +71,11 @@ Raw content is available in template blocks as the ``CONTENT`` variable. <h1>My cool blog</h1> {% block entry %} <h2>{{ TITLE }}</h2> - {% if DATE %}<h4>Published in: {{ DATE }}</h4>{% endif %} + {% if DATE_FORMATTED %}<h4>Published in: {{ DATE_FORMATTED }}</h4>{% endif %} <pre>{{ CONTENT }}</pre> {% endblock %} {% block listing_once %}<ul>{% endblock %} - {% block listing %}<p><a href="{{ FILENAME }}.html">{{ TITLE }}</a>{% if DATE %} - {{ DATE }}{% endif %}</p>{% endblock %} + {% block listing %}<p><a href="{{ FILENAME }}.html">{{ TITLE }}</a>{% if DATE_FORMATTED %} - {{ DATE_FORMATTED }}{% endif %}</p>{% endblock %} {% block listing_once %}</ul>{% endblock %} </body> </html> diff --git a/configure.ac b/configure.ac index 040eb44..716daa7 100644 --- a/configure.ac +++ b/configure.ac @@ -9,6 +9,8 @@ AC_CONFIG_HEADERS([config.h]) AM_SILENT_RULES([yes]) AM_MAINTAINER_MODE([enable]) +AC_USE_SYSTEM_EXTENSIONS + LT_INIT AC_PROG_CC_C99 @@ -54,7 +56,7 @@ AS_IF([test "x$have_cmocka" = "xyes"], , [ ]) AM_CONDITIONAL([USE_CMOCKA], [test "x$have_cmocka" = "xyes"]) -AC_CHECK_HEADERS([sys/types.h sys/stat.h]) +AC_CHECK_HEADERS([sys/types.h sys/stat.h time.h]) AC_CONFIG_FILES([ Makefile @@ -147,10 +147,12 @@ main(int argc, char **argv) goto cleanup; } for (unsigned int j = 0; pieces[0][j] != '\0'; j++) { - if (!(pieces[0][j] >= 'A' && pieces[0][j] <= 'Z')) { + if (!((pieces[0][j] >= 'A' && pieces[0][j] <= 'Z') || + pieces[0][j] == '_')) + { fprintf(stderr, "blogc: error: invalid value " - "for -D (configuration key must be uppercase): " - "%s\n", pieces[0]); + "for -D (configuration key must be uppercase " + "with '_'): %s\n", pieces[0]); b_strv_free(pieces); rv = 2; goto cleanup; diff --git a/src/renderer.c b/src/renderer.c index 905c42f..ac269b8 100644 --- a/src/renderer.c +++ b/src/renderer.c @@ -10,13 +10,65 @@ #include <config.h> #endif /* HAVE_CONFIG_H */ +#ifdef HAVE_TIME_H +#include <time.h> +#endif /* HAVE_TIME_H */ + +#include <stdio.h> #include <string.h> #include "utils/utils.h" +#include "loader.h" #include "source-parser.h" #include "template-parser.h" #include "renderer.h" +const char* +blogc_get_variable(const char *name, b_trie_t *global, b_trie_t *local) +{ + const char *rv = NULL; + if (local != NULL) { + rv = b_trie_lookup(local, name); + if (rv != NULL) + return rv; + } + if (global != NULL) + rv = b_trie_lookup(global, name); + return rv; +} + + +char* +blogc_format_date(b_trie_t *global, b_trie_t *local) +{ + const char *date = blogc_get_variable("DATE", global, local); + const char *date_format = blogc_get_variable("DATE_FORMAT", global, local); + if (date == NULL) + return NULL; + if (date_format == NULL) + return b_strdup(date); +#ifdef HAVE_TIME_H + struct tm tm; + memset(&tm, 0, sizeof(struct tm)); + if (NULL == strptime(date, "%Y-%m-%d %H:%M:%S", &tm)) { + fprintf(stderr, "blogc: warning: Failed to parse DATE variable: %s\n", + date); + return b_strdup(date); + } + char tmp[1024]; + if (0 == strftime(tmp, sizeof(tmp), date_format, &tm)) { + fprintf(stderr, "blogc: warning: Failed to format DATE variable, " + "FORMAT is too long: %s\n", date_format); + return b_strdup(date); + } + return b_strdup(tmp); +#else + fprintf(stderr, "blogc: warning: Can't pre-process DATE variable.\n"); + return NULL; +#endif +} + + char* blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config, bool listing) { @@ -29,7 +81,8 @@ blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config, bool listing b_string_t *str = b_string_new(); b_trie_t *tmp_source = NULL; - char *config_value = NULL; + const char *config_value = NULL; + char *config_value2 = NULL; unsigned int if_count = 0; unsigned int if_skip = 0; @@ -88,23 +141,19 @@ 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) { - - // try local config first - if (tmp_source != NULL) { - config_value = b_trie_lookup(tmp_source, stmt->value); - if (config_value != NULL) { - b_string_append(str, config_value); + if (0 == strcmp(stmt->value, "DATE_FORMATTED")) { + config_value2 = blogc_format_date(config, tmp_source); + if (config_value2 != NULL) { + b_string_append(str, config_value2); + free(config_value2); + config_value2 = NULL; break; } } - - // if not found, try global config - if (config != NULL) { - config_value = b_trie_lookup(config, stmt->value); - if (config_value != NULL) { + else { + config_value = blogc_get_variable(stmt->value, config, tmp_source); + if (config_value != NULL) b_string_append(str, config_value); - break; - } } } break; @@ -127,10 +176,16 @@ blogc_render(b_slist_t *tmpl, b_slist_t *sources, b_trie_t *config, bool listing case BLOGC_TEMPLATE_IF_STMT: defined = false; if (stmt->value != NULL) { - if (tmp_source != NULL && b_trie_lookup(tmp_source, stmt->value) != NULL) - defined = true; - if (config != NULL && b_trie_lookup(config, stmt->value) != NULL) - defined = true; + if (0 == strcmp(stmt->value, "DATE_FORMATTED")) { + config_value2 = blogc_format_date(config, tmp_source); + if (config_value2 != NULL) { + defined = true; + free(config_value2); + config_value2 = NULL; + } + } + else + defined = blogc_get_variable(stmt->value, config, tmp_source) != NULL; } if ((!if_not && !defined) || (if_not && defined)) { if_skip = if_count; diff --git a/src/renderer.h b/src/renderer.h index c9a0ed1..e4ad4a1 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -12,6 +12,8 @@ #include <stdbool.h> #include "utils/utils.h" +const char* blogc_get_variable(const char *name, b_trie_t *global, b_trie_t *local); +char* blogc_format_date(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/tests/check_renderer.c b/tests/check_renderer.c index f8acc14..681b821 100644 --- a/tests/check_renderer.c +++ b/tests/check_renderer.c @@ -28,10 +28,13 @@ create_sources(unsigned int count) const char *s[] = { "BOLA: asd\n" "GUDA: zxc\n" + "DATE: 2015-01-02 03:04:05\n" + "DATE_FORMAT: %R\n" "-----\n" "ahahahahahahahaha", "BOLA: asd2\n" "GUDA: zxc2\n" + "DATE: 2014-02-03 04:05:06\n" "-----\n" "ahahahahahahahaha2", "BOLA: asd3\n" @@ -58,6 +61,8 @@ test_render_entry(void **state) "foo\n" "{% block listing_once %}fuuu{% endblock %}\n" "{% block entry %}\n" + "{{ DATE }}\n" + "{% if DATE_FORMATTED %}{{ DATE_FORMATTED }}{% endif %}\n" "{% if GUDA %}{{ GUDA }}{% endif %}\n" "{% if CHUNDA %}{{ CHUNDA }}{% endif %}\n" "{% endblock %}\n" @@ -73,6 +78,8 @@ test_render_entry(void **state) "foo\n" "\n" "\n" + "2015-01-02 03:04:05\n" + "03:04\n" "zxc\n" "\n" "\n" @@ -94,6 +101,7 @@ test_render_listing(void **state) "{% if CHUNDA %}{{ CHUNDA }}{% endif %}\n" "{% endblock %}\n" "{% block listing %}\n" + "{% if DATE_FORMATTED %}{{ DATE_FORMATTED }}{% endif %}\n" "bola: {% if BOLA %}{{ BOLA }}{% endif %}\n" "{% endblock %}\n"; blogc_error_t *err = NULL; @@ -108,10 +116,13 @@ test_render_listing(void **state) "fuuu\n" "\n" "\n" + "03:04\n" "bola: asd\n" "\n" + "2014-02-03 04:05:06\n" "bola: asd2\n" "\n" + "\n" "bola: asd3\n" "\n"); blogc_template_free_stmts(l); @@ -319,6 +330,109 @@ test_render_prefer_local_variable(void **state) } +static void +test_get_variable(void **state) +{ + b_trie_t *g = b_trie_new(free); + b_trie_insert(g, "NAME", b_strdup("bola")); + b_trie_insert(g, "TITLE", b_strdup("bola2")); + b_trie_t *l = b_trie_new(free); + b_trie_insert(l, "NAME", b_strdup("chunda")); + b_trie_insert(l, "TITLE", b_strdup("chunda2")); + assert_string_equal(blogc_get_variable("NAME", g, l), "chunda"); + assert_string_equal(blogc_get_variable("TITLE", g, l), "chunda2"); + assert_null(blogc_get_variable("BOLA", g, l)); + b_trie_free(g); + b_trie_free(l); +} + + +static void +test_get_variable_only_local(void **state) +{ + b_trie_t *g = NULL; + b_trie_t *l = b_trie_new(free); + b_trie_insert(l, "NAME", b_strdup("chunda")); + b_trie_insert(l, "TITLE", b_strdup("chunda2")); + assert_string_equal(blogc_get_variable("NAME", g, l), "chunda"); + assert_string_equal(blogc_get_variable("TITLE", g, l), "chunda2"); + assert_null(blogc_get_variable("BOLA", g, l)); + b_trie_free(l); +} + + +static void +test_get_variable_only_global(void **state) +{ + b_trie_t *g = b_trie_new(free); + b_trie_insert(g, "NAME", b_strdup("bola")); + b_trie_insert(g, "TITLE", b_strdup("bola2")); + b_trie_t *l = NULL; + assert_string_equal(blogc_get_variable("NAME", g, l), "bola"); + assert_string_equal(blogc_get_variable("TITLE", g, l), "bola2"); + assert_null(blogc_get_variable("BOLA", g, l)); + b_trie_free(g); +} + + +static void +test_format_date(void **state) +{ + b_trie_t *g = b_trie_new(free); + b_trie_insert(g, "DATE_FORMAT", b_strdup("%H -- %j")); + b_trie_t *l = b_trie_new(free); + b_trie_insert(l, "DATE", b_strdup("2015-01-02 03:04:05")); + b_trie_insert(l, "DATE_FORMAT", b_strdup("%R")); + char *date = blogc_format_date(g, l); + assert_string_equal(date, "03:04"); + free(date); + b_trie_free(g); + b_trie_free(l); +} + + +static void +test_format_date_with_global_format(void **state) +{ + b_trie_t *g = b_trie_new(free); + b_trie_insert(g, "DATE_FORMAT", b_strdup("%H -- %j")); + b_trie_t *l = b_trie_new(free); + b_trie_insert(l, "DATE", b_strdup("2015-01-02 03:04:05")); + char *date = blogc_format_date(g, l); + assert_string_equal(date, "03 -- 002"); + free(date); + b_trie_free(g); + b_trie_free(l); +} + + +static void +test_format_date_without_format(void **state) +{ + b_trie_t *g = b_trie_new(free); + b_trie_t *l = b_trie_new(free); + b_trie_insert(l, "DATE", b_strdup("2015-01-02 03:04:05")); + char *date = blogc_format_date(g, l); + assert_string_equal(date, "2015-01-02 03:04:05"); + free(date); + b_trie_free(g); + b_trie_free(l); +} + + +static void +test_format_date_without_date(void **state) +{ + b_trie_t *g = b_trie_new(free); + b_trie_t *l = b_trie_new(free); + char *date = blogc_format_date(g, l); + assert_null(date); + free(date); + b_trie_free(g); + b_trie_free(l); +} + + int main(void) { @@ -332,6 +446,13 @@ main(void) unit_test(test_render_outside_block), unit_test(test_render_null), unit_test(test_render_prefer_local_variable), + unit_test(test_get_variable), + unit_test(test_get_variable_only_local), + unit_test(test_get_variable_only_global), + unit_test(test_format_date), + unit_test(test_format_date_with_global_format), + unit_test(test_format_date_without_format), + unit_test(test_format_date_without_date), }; return run_tests(tests); } |