aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRafael G. Martins <rafael@rafaelmartins.eng.br>2015-12-29 00:12:51 +0100
committerRafael G. Martins <rafael@rafaelmartins.eng.br>2015-12-29 00:13:47 +0100
commit8d96c02e5118cf7bd656fde9100570a67115d19a (patch)
treea3c638bab8f8e595a10ff9751bbe4c8a603a918d /src
parent14e9d7b2299f15efb695b0202f9c1f6a9f7a4ba6 (diff)
downloadblogc-8d96c02e5118cf7bd656fde9100570a67115d19a.tar.gz
blogc-8d96c02e5118cf7bd656fde9100570a67115d19a.tar.bz2
blogc-8d96c02e5118cf7bd656fde9100570a67115d19a.zip
man: renderer: template-parser: added foreach iterator support
Diffstat (limited to 'src')
-rw-r--r--src/renderer.c71
-rw-r--r--src/renderer.h2
-rw-r--r--src/template-parser.c67
-rw-r--r--src/template-parser.h2
4 files changed, 141 insertions, 1 deletions
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,