From 49ed30a5e87e510fd0c14b367110175f9d2fb144 Mon Sep 17 00:00:00 2001 From: "Rafael G. Martins" Date: Sat, 9 Feb 2019 02:29:05 +0100 Subject: blogc: template: allow whitespaces in template tags, not just spaces --- src/blogc/template-parser.c | 31 +++++---- src/common/utils.c | 8 +++ src/common/utils.h | 1 + tests/blogc/check_template_parser.c | 130 ++++++++++++++++++++++++++++++++++++ 4 files changed, 154 insertions(+), 16 deletions(-) diff --git a/src/blogc/template-parser.c b/src/blogc/template-parser.c index c3e9a5c..a53f1aa 100644 --- a/src/blogc/template-parser.c +++ b/src/blogc/template-parser.c @@ -161,7 +161,7 @@ blogc_template_parse(const char *src, size_t src_len, bc_error_t **err) state = TEMPLATE_BLOCK_START; case TEMPLATE_BLOCK_START: - if (c == ' ') + if (bc_isspace(c)) break; if (c >= 'a' && c <= 'z') { state = TEMPLATE_BLOCK_TYPE; @@ -183,7 +183,7 @@ blogc_template_parse(const char *src, size_t src_len, bc_error_t **err) case TEMPLATE_BLOCK_TYPE: if (c >= 'a' && c <= 'z') break; - if (c == ' ') { + if (bc_isspace(c)) { if ((current - start == 5) && (0 == strncmp("block", src + start, 5))) { @@ -339,7 +339,7 @@ blogc_template_parse(const char *src, size_t src_len, bc_error_t **err) break; case TEMPLATE_BLOCK_BLOCK_TYPE_START: - if (c == ' ') + if (bc_isspace(c)) break; if (c >= 'a' && c <= 'z') { state = TEMPLATE_BLOCK_BLOCK_TYPE; @@ -354,7 +354,7 @@ blogc_template_parse(const char *src, size_t src_len, bc_error_t **err) case TEMPLATE_BLOCK_BLOCK_TYPE: if ((c >= 'a' && c <= 'z') || c == '_') break; - if (c == ' ') { + if (bc_isspace(c)) { if ((current - start == 5) && (0 == strncmp("entry", src + start, 5))) { @@ -387,7 +387,7 @@ blogc_template_parse(const char *src, size_t src_len, bc_error_t **err) break; case TEMPLATE_BLOCK_IF_START: - if (c == ' ') + if (bc_isspace(c)) break; if (c >= 'A' && c <= 'Z') { state = TEMPLATE_BLOCK_IF_VARIABLE; @@ -402,7 +402,7 @@ blogc_template_parse(const char *src, size_t src_len, bc_error_t **err) case TEMPLATE_BLOCK_IF_VARIABLE: if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_') break; - if (c == ' ') { + if (bc_isspace(c)) { end = current; if (type == BLOGC_TEMPLATE_NODE_IF) state = TEMPLATE_BLOCK_IF_OPERATOR_START; @@ -417,22 +417,21 @@ blogc_template_parse(const char *src, size_t src_len, bc_error_t **err) break; case TEMPLATE_BLOCK_IF_OPERATOR_START: - if (c == ' ') { + if (bc_isspace(c)) break; - } state = TEMPLATE_BLOCK_IF_OPERATOR; op_start = current; break; case TEMPLATE_BLOCK_IF_OPERATOR: - if (c != ' ') + if (!bc_isspace(c)) break; state = TEMPLATE_BLOCK_IF_OPERAND_START; op_end = current; break; case TEMPLATE_BLOCK_IF_OPERAND_START: - if (c == ' ') + if (bc_isspace(c)) break; if (c >= 'A' && c <= 'Z') { state = TEMPLATE_BLOCK_IF_VARIABLE_OPERAND; @@ -469,7 +468,7 @@ blogc_template_parse(const char *src, size_t src_len, bc_error_t **err) break; case TEMPLATE_BLOCK_FOREACH_START: - if (c == ' ') + if (bc_isspace(c)) break; if (c >= 'A' && c <= 'Z') { state = TEMPLATE_BLOCK_FOREACH_VARIABLE; @@ -485,7 +484,7 @@ blogc_template_parse(const char *src, size_t src_len, bc_error_t **err) case TEMPLATE_BLOCK_FOREACH_VARIABLE: if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_') break; - if (c == ' ') { + if (bc_isspace(c)) { end = current; state = TEMPLATE_BLOCK_END_WHITESPACE_CLEANER; break; @@ -497,7 +496,7 @@ blogc_template_parse(const char *src, size_t src_len, bc_error_t **err) break; case TEMPLATE_BLOCK_END_WHITESPACE_CLEANER: - if (c == ' ') + if (bc_isspace(c)) break; if (c == '-') { lstrip_next = true; @@ -524,7 +523,7 @@ blogc_template_parse(const char *src, size_t src_len, bc_error_t **err) break; case TEMPLATE_VARIABLE_START: - if (c == ' ') + if (bc_isspace(c)) break; if (c >= 'A' && c <= 'Z') { state = TEMPLATE_VARIABLE; @@ -540,7 +539,7 @@ blogc_template_parse(const char *src, size_t src_len, bc_error_t **err) case TEMPLATE_VARIABLE: if ((c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_') break; - if (c == ' ') { + if (bc_isspace(c)) { end = current; state = TEMPLATE_VARIABLE_END; break; @@ -557,7 +556,7 @@ blogc_template_parse(const char *src, size_t src_len, bc_error_t **err) break; case TEMPLATE_VARIABLE_END: - if (c == ' ') + if (bc_isspace(c)) break; if (c == '}') { state = TEMPLATE_CLOSE_BRACKET; diff --git a/src/common/utils.c b/src/common/utils.c index 530ab6c..692d1ce 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -167,6 +167,14 @@ bc_strdup_printf(const char *format, ...) } +// locale-independent implementation of isspace +bool +bc_isspace(int c) +{ + return c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v'; +} + + bool bc_str_starts_with(const char *str, const char *prefix) { diff --git a/src/common/utils.h b/src/common/utils.h index bc3a157..94c3356 100644 --- a/src/common/utils.h +++ b/src/common/utils.h @@ -42,6 +42,7 @@ char* bc_strdup(const char *s); char* bc_strndup(const char *s, size_t n); char* bc_strdup_vprintf(const char *format, va_list ap); char* bc_strdup_printf(const char *format, ...); +bool bc_isspace(int c); bool bc_str_starts_with(const char *str, const char *prefix); bool bc_str_ends_with(const char *str, const char *suffix); char* bc_str_lstrip(char *str); diff --git a/tests/blogc/check_template_parser.c b/tests/blogc/check_template_parser.c index bf9f6d7..0121f73 100644 --- a/tests/blogc/check_template_parser.c +++ b/tests/blogc/check_template_parser.c @@ -338,6 +338,135 @@ test_template_parse_html(void **state) } +static void +test_template_parse_html_whitespace(void **state) +{ + const char *a = + "\n" + " \n" + " {%\n block entry\n%}\n" + " My cool blog >> {{ TITLE }}\n" + " {% \vendblock\v %}\n" + " {% \r\nblock listing_once\n%}\n" + " My cool blog - Main page\n" + " {%\t endblock\t%}\n" + " \n" + " \n" + "

My cool blog

\n" + " {%\t\t\tblock entry\n%}\n" + "

{{\tTITLE\n}}

\n" + " {%\nifdef DATE\v%}

Published in: {{\tDATE\t}}

{%\fendif\f%}\n" + "
{{\tCONTENT\n}}
\n" + " {%\n\n \nendblock\f\f\n\t%}\n" + " {%\nblock\n\nlisting_once\t%}{%\nendblock\n%}\n" + " \n" + "\n"; + bc_error_t *err = NULL; + bc_slist_t *ast = blogc_template_parse(a, strlen(a), &err); + assert_null(err); + assert_non_null(ast); + blogc_assert_template_node(ast, "\n \n ", + BLOGC_TEMPLATE_NODE_CONTENT); + blogc_assert_template_node(ast->next, "entry", + BLOGC_TEMPLATE_NODE_BLOCK); + blogc_assert_template_node(ast->next->next, + "\n My cool blog >> ", BLOGC_TEMPLATE_NODE_CONTENT); + blogc_assert_template_node(ast->next->next->next, "TITLE", + BLOGC_TEMPLATE_NODE_VARIABLE); + blogc_assert_template_node(ast->next->next->next->next, + "\n ", BLOGC_TEMPLATE_NODE_CONTENT); + blogc_assert_template_node(ast->next->next->next->next->next, NULL, + BLOGC_TEMPLATE_NODE_ENDBLOCK); + blogc_assert_template_node(ast->next->next->next->next->next->next, + "\n ", BLOGC_TEMPLATE_NODE_CONTENT); + blogc_assert_template_node(ast->next->next->next->next->next->next->next, + "listing_once", BLOGC_TEMPLATE_NODE_BLOCK); + bc_slist_t *tmp = ast->next->next->next->next->next->next->next->next; + blogc_assert_template_node(tmp, + "\n My cool blog - Main page\n ", + BLOGC_TEMPLATE_NODE_CONTENT); + blogc_assert_template_node(tmp->next, NULL, BLOGC_TEMPLATE_NODE_ENDBLOCK); + blogc_assert_template_node(tmp->next->next, + "\n \n \n

My cool blog

\n ", + BLOGC_TEMPLATE_NODE_CONTENT); + blogc_assert_template_node(tmp->next->next->next, "entry", + BLOGC_TEMPLATE_NODE_BLOCK); + blogc_assert_template_node(tmp->next->next->next->next, + "\n

", BLOGC_TEMPLATE_NODE_CONTENT); + blogc_assert_template_node(tmp->next->next->next->next->next, + "TITLE", BLOGC_TEMPLATE_NODE_VARIABLE); + blogc_assert_template_node(tmp->next->next->next->next->next->next, + "

\n ", BLOGC_TEMPLATE_NODE_CONTENT); + blogc_assert_template_node(tmp->next->next->next->next->next->next->next, + "DATE", BLOGC_TEMPLATE_NODE_IFDEF); + tmp = tmp->next->next->next->next->next->next->next->next; + blogc_assert_template_node(tmp, "

Published in: ", + BLOGC_TEMPLATE_NODE_CONTENT); + blogc_assert_template_node(tmp->next, "DATE", BLOGC_TEMPLATE_NODE_VARIABLE); + blogc_assert_template_node(tmp->next->next, "

", + BLOGC_TEMPLATE_NODE_CONTENT); + blogc_assert_template_node(tmp->next->next->next, NULL, + BLOGC_TEMPLATE_NODE_ENDIF); + blogc_assert_template_node(tmp->next->next->next->next, "\n
",
+        BLOGC_TEMPLATE_NODE_CONTENT);
+    blogc_assert_template_node(tmp->next->next->next->next->next,
+        "CONTENT", BLOGC_TEMPLATE_NODE_VARIABLE);
+    blogc_assert_template_node(tmp->next->next->next->next->next->next,
+        "
\n ", BLOGC_TEMPLATE_NODE_CONTENT); + blogc_assert_template_node(tmp->next->next->next->next->next->next->next, + NULL, BLOGC_TEMPLATE_NODE_ENDBLOCK); + tmp = tmp->next->next->next->next->next->next->next->next; + blogc_assert_template_node(tmp, "\n ", BLOGC_TEMPLATE_NODE_CONTENT); + blogc_assert_template_node(tmp->next, "listing_once", + BLOGC_TEMPLATE_NODE_BLOCK); + blogc_assert_template_node(tmp->next->next, "", + BLOGC_TEMPLATE_NODE_CONTENT); + blogc_assert_template_node(tmp->next->next->next->next, NULL, + BLOGC_TEMPLATE_NODE_ENDBLOCK); + blogc_assert_template_node(tmp->next->next->next->next->next, + "\n \n\n", BLOGC_TEMPLATE_NODE_CONTENT); + assert_null(tmp->next->next->next->next->next->next); + blogc_template_free_ast(ast); +} + + static void test_template_parse_ifdef_and_var_outside_block(void **state) { @@ -1137,6 +1266,7 @@ main(void) unit_test(test_template_parse), unit_test(test_template_parse_crlf), unit_test(test_template_parse_html), + unit_test(test_template_parse_html_whitespace), unit_test(test_template_parse_ifdef_and_var_outside_block), unit_test(test_template_parse_nested_else), unit_test(test_template_parse_invalid_block_start), -- cgit v1.2.3-18-g5258