From fb5a52884dd17d17bab47de7f53c17c05ced6e1b Mon Sep 17 00:00:00 2001 From: Tomas Bzatek Date: Sat, 4 Jun 2011 17:30:12 +0200 Subject: Introduce conditional system This is very basic scripting support - simple value retrieval and block conditionals. Defines could be either static from theme setup or programatically added during page generation. --- src/block-parser.c | 133 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 114 insertions(+), 19 deletions(-) (limited to 'src/block-parser.c') diff --git a/src/block-parser.c b/src/block-parser.c index d4fcccb..cfe9047 100644 --- a/src/block-parser.c +++ b/src/block-parser.c @@ -23,7 +23,6 @@ #include #include -#include #include "block-parser.h" #include "gallery-utils.h" @@ -38,6 +37,8 @@ struct BlockParser { GHashTable *table; GQueue *active_tree; gchar *current_line; + GHashTable *conditionals; + guint ignore_level; }; typedef struct { @@ -45,6 +46,10 @@ typedef struct { gchar *data; gboolean used; gboolean finished; + + gboolean is_conditional; + gchar *conditional_key; + gboolean should_ignore; } BlockData; @@ -59,6 +64,7 @@ block_parser_destroy_notify (gpointer data) g_free (d->replace_key); g_free (d->data); + g_free (d->conditional_key); g_free (d); } @@ -84,6 +90,17 @@ block_parser_free (BlockParser *parser) g_free (parser); } +/* + * block_parser_set_conditionals: set a hash table to be used for conditionals lookup + * + */ +void +block_parser_set_conditionals (BlockParser *parser, GHashTable *conditionals) +{ + g_return_if_fail (parser != NULL); + + parser->conditionals = conditionals; +} /* * block_parser_register_key: tell parser to expect the key to catch @@ -103,10 +120,10 @@ block_parser_register_key (BlockParser *parser, const gchar *key, const gchar *r if (replace_key) data->replace_key = g_strdup_printf ("", replace_key); data->used = TRUE; /* buffer is empty, mask it for block_parser_has_unused_data() */ + data->is_conditional = FALSE; g_hash_table_replace (parser->table, g_strdup (key), data); } - /* * block_parser_get_data: return retrieved data or NULL if none read yet * returns newly allocated string, caller is responsible for freeing @@ -174,8 +191,18 @@ push_string (BlockParser *parser, const gchar *piece) { BlockData *data; gchar *s; + guint i; - data = g_queue_peek_head (parser->active_tree); + /* Test if the data should be ignored */ + if (parser->ignore_level > 0) + return; + + /* Not ignoring, find first non-conditional record */ + for (i = 0; (data = g_queue_peek_nth (parser->active_tree, i)) != NULL; i++) + if (! data->is_conditional) + break; + + /* Actually push the string */ if (data) { if (data->data) s = g_strdup_printf ("%s%s", data->data, piece); @@ -192,6 +219,25 @@ push_string (BlockParser *parser, const gchar *piece) } } +static gchar * +extract_arg (const gchar *str) +{ + const gchar *start; + const gchar *end; + + start = strstr (str, "("); + if (start == NULL) + return NULL; + start++; + + end = strstr (str, ")"); + if (end == NULL) + return NULL; + end++; + + return g_strndup (start, end - start - 1); +} + /* * block_parser_read_and_parse: reads input from the file and returns parsed line * - if there's a multiline block, string before the opening placeholder and @@ -210,8 +256,8 @@ block_parser_read_and_parse (BlockParser *parser, FILE *stream) gchar *token; gchar *start, *end; gchar *s; - GList *keys; - GList *l; + GHashTableIter iter; + gchar *key; BlockData *data; gboolean handled; @@ -224,8 +270,6 @@ block_parser_read_and_parse (BlockParser *parser, FILE *stream) } parser->current_line = g_strdup (""); - keys = g_hash_table_get_keys (parser->table); - /* find tokens */ b = buffer; while ((token = get_next_token (b, &start, &end, NULL))) { @@ -236,25 +280,77 @@ block_parser_read_and_parse (BlockParser *parser, FILE *stream) push_string (parser, s); g_free (s); + /* match conditionals */ + if (parser->conditionals && (g_str_has_prefix (token, "ifdef(") || g_str_has_prefix (token, "ifndef("))) { + data = g_new0 (BlockData, 1); + data->is_conditional = TRUE; + data->conditional_key = extract_arg (token); + data->should_ignore = ((g_str_has_prefix (token, "ifdef(") && g_hash_table_lookup (parser->conditionals, data->conditional_key) == NULL) || + (g_str_has_prefix (token, "ifndef(") && g_hash_table_lookup (parser->conditionals, data->conditional_key) != NULL)); + if (data->should_ignore && parser->ignore_level == 0) + parser->ignore_level = 1; + else + if (parser->ignore_level > 0) + parser->ignore_level++; + g_queue_push_head (parser->active_tree, data); + handled = TRUE; + } + + if (parser->conditionals && g_str_has_prefix (token, "endif(")) { + s = extract_arg (token); + data = g_queue_peek_head (parser->active_tree); + if (data == NULL || !data->is_conditional || strcmp (data->conditional_key, s) != 0) { + log_error ("block_parser_read_and_parse: something is wrong with the parser table: expected '%s' but got '%s'\n", s, data->conditional_key); + } + else { + g_queue_pop_head (parser->active_tree); + if (parser->ignore_level > 0) + parser->ignore_level--; + block_parser_destroy_notify (data); + handled = TRUE; + } + g_free (s); + } + + if (parser->conditionals && g_str_has_prefix (token, "else(")) { + s = extract_arg (token); + data = g_queue_peek_head (parser->active_tree); + if (data == NULL || !data->is_conditional || strcmp (data->conditional_key, s) != 0) { + log_error ("block_parser_read_and_parse: something is wrong with the parser table: expected '%s' but got '%s'\n", s, data->conditional_key); + } + else { + data->should_ignore = ! data->should_ignore; + /* if we're not ignoring, level is zero, let's start ignoring by setting to one */ + if (data->should_ignore && parser->ignore_level == 0) + parser->ignore_level = 1; + else + /* if we're ignoring but should not, let's go down to zero */ + if (! data->should_ignore && parser->ignore_level == 1) + parser->ignore_level = 0; + /* in all other cases (level > 1) we're ignoring already and we're not the topmost block, so let's keep being ignored */ + handled = TRUE; + } + g_free (s); + } + /* match known tags */ - for (l = keys; l != NULL; l = l->next) { + g_hash_table_iter_init (&iter, parser->table); + while (!handled && g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &data)) { /* test BEGIN_ tokens */ - s = g_strdup_printf ("BEGIN_%s", (gchar *) l->data); - if (strcmp (s, token) == 0) { - data = g_hash_table_lookup (parser->table, (gchar *) l->data); - if (data) { - g_queue_push_head (parser->active_tree, data); - handled = TRUE; - } + s = g_strdup_printf ("BEGIN_%s", key); + if (strcmp (s, token) == 0 && data) { + g_queue_push_head (parser->active_tree, data); + handled = TRUE; } g_free (s); + if (handled) + break; /* test END_ tokens */ - s = g_strdup_printf ("END_%s", (gchar *) l->data); + s = g_strdup_printf ("END_%s", key); if (strcmp (s, token) == 0) { - data = g_hash_table_lookup (parser->table, (gchar *) l->data); if (data == NULL || data != g_queue_peek_head (parser->active_tree)) { - log_error ("block_parser_read_and_parse: something is wrong with the parser table: expected '%s'\n", (gchar *) l->data); + log_error ("block_parser_read_and_parse: something is wrong with the parser table: expected '%s'\n", key); } else { g_queue_pop_head (parser->active_tree); @@ -282,7 +378,6 @@ block_parser_read_and_parse (BlockParser *parser, FILE *stream) /* push rest of the buffer till the end of the line */ push_string (parser, b); - g_list_free (keys); g_free (buffer); return parser->current_line; } -- cgit v1.2.3