diff options
| author | Tomas Bzatek <tbzatek@users.sourceforge.net> | 2012-12-24 20:10:27 +0100 |
|---|---|---|
| committer | Tomas Bzatek <tbzatek@users.sourceforge.net> | 2012-12-24 20:10:27 +0100 |
| commit | c5e75352f27a02501b3a1a9189f10a581c12e7fb (patch) | |
| tree | b3bdae02b91bbb7ab4f5bb48b9704dbf378ce533 | |
| parent | dff418800174265b1a591ac44eb244e2b16f94a5 (diff) | |
| download | cataract-c5e75352f27a02501b3a1a9189f10a581c12e7fb.tar.xz | |
block-parser: Add support for custom block functions
Similar to replace-table custom functions, this brings an ability
to register custom block functions that can be called from templates
with variable arguments.
The syntax is as follows:
<!-- $(if (function_name(arg1, "arg2", 'arg3'))) -->
...
<!-- $(endif (function_name(arg1, "arg2", 'arg3'))) -->
An optional exclamation mark before the function name reverts the result
(negates) the predicate.
This allows template flexibility with respect to the currently processed image.
| -rw-r--r-- | src/block-parser.c | 57 | ||||
| -rw-r--r-- | src/block-parser.h | 11 | ||||
| -rw-r--r-- | src/replace-table.c | 83 | ||||
| -rw-r--r-- | src/replace-table.h | 7 |
4 files changed, 128 insertions, 30 deletions
diff --git a/src/block-parser.c b/src/block-parser.c index 0697d2a..8aa882a 100644 --- a/src/block-parser.c +++ b/src/block-parser.c @@ -38,6 +38,7 @@ struct BlockParser { GQueue *active_tree; gchar *current_line; GHashTable *conditionals; + GHashTable *functions; guint ignore_level; }; @@ -48,10 +49,15 @@ typedef struct { gboolean finished; gboolean is_conditional; + gboolean is_conditional_function; gchar *conditional_key; gboolean should_ignore; } BlockData; +typedef struct { + BlockParserConditionalFunction callback; + gpointer user_data; +} BlockParserFuncData; static void @@ -75,6 +81,7 @@ block_parser_new () parser = g_new0 (BlockParser, 1); parser->table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, block_parser_destroy_notify); + parser->functions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); parser->active_tree = g_queue_new (); return parser; @@ -85,6 +92,7 @@ block_parser_free (BlockParser *parser) { g_return_if_fail (parser != NULL); + g_hash_table_destroy (parser->functions); g_hash_table_destroy (parser->table); g_queue_free (parser->active_tree); g_free (parser); @@ -125,6 +133,24 @@ block_parser_register_key (BlockParser *parser, const gchar *key, const gchar *r } /* + * block_parser_register_function: function called to determine whether a block should be ignored or not + * + */ +void +block_parser_register_function (BlockParser *parser, const gchar *conditional_name, BlockParserConditionalFunction callback, gpointer user_data) +{ + BlockParserFuncData *func_data; + + g_return_if_fail (parser != NULL); + + func_data = g_malloc0 (sizeof (BlockParserFuncData)); + func_data->callback = callback; + func_data->user_data = user_data; + + g_hash_table_insert (parser->functions, g_strdup (conditional_name), func_data); +} + +/* * block_parser_get_data: return retrieved data or NULL if none read yet * returns newly allocated string, caller is responsible for freeing * @@ -241,6 +267,9 @@ block_parser_read_and_parse (BlockParser *parser, FILE *stream) gchar *key; BlockData *data; gboolean handled; + gchar **args; + gboolean negation; + BlockParserFuncData *func_data; g_return_val_if_fail (parser != NULL, NULL); @@ -262,12 +291,34 @@ block_parser_read_and_parse (BlockParser *parser, FILE *stream) g_free (s); /* match conditionals */ - if (parser->conditionals && (token_has_prefix (token, "ifdef") || token_has_prefix (token, "ifndef"))) { + if ((parser->conditionals && (token_has_prefix (token, "ifdef") || token_has_prefix (token, "ifndef"))) || + token_has_prefix (token, "if")) + { data = g_new0 (BlockData, 1); data->is_conditional = TRUE; + data->is_conditional_function = token_has_prefix (token, "if"); data->conditional_key = extract_token_arg (token); - data->should_ignore = ((token_has_prefix (token, "ifdef") && g_hash_table_lookup (parser->conditionals, data->conditional_key) == NULL) || - (token_has_prefix (token, "ifndef") && g_hash_table_lookup (parser->conditionals, data->conditional_key) != NULL)); + + if (! data->is_conditional_function) { + data->should_ignore = ((token_has_prefix (token, "ifdef") && g_hash_table_lookup (parser->conditionals, data->conditional_key) == NULL) || + (token_has_prefix (token, "ifndef") && g_hash_table_lookup (parser->conditionals, data->conditional_key) != NULL)); + } else { + s = parse_function (data->conditional_key, &args, &negation); + data->should_ignore = TRUE; + if (s == NULL) { + log_error ("block_parser_read_and_parse: invalid conditional function specified: '%s'\n", data->conditional_key); + } else { + func_data = g_hash_table_lookup (parser->functions, s); + if (func_data) { /* when not found, ignore the block as the function cannot be called */ + data->should_ignore = ! func_data->callback (args, func_data->user_data); + if (negation) + data->should_ignore = ! data->should_ignore; + } + g_strfreev (args); + g_free (s); + } + } + if (data->should_ignore && parser->ignore_level == 0) parser->ignore_level = 1; else diff --git a/src/block-parser.h b/src/block-parser.h index 96c7fb8..edf6dd2 100644 --- a/src/block-parser.h +++ b/src/block-parser.h @@ -26,6 +26,11 @@ G_BEGIN_DECLS typedef struct BlockParser BlockParser; +/* + * conditional function callback, arguments passed as strings. Returning TRUE means not to ignore the block. + */ +typedef gboolean (*BlockParserConditionalFunction) (gchar **args, gpointer user_data); + BlockParser * block_parser_new (); @@ -47,6 +52,12 @@ void block_parser_set_conditionals (BlockParser *parser, GHashTable *conditional void block_parser_register_key (BlockParser *parser, const gchar *key, const gchar *replace_key); /* + * block_parser_register_function: function called to determine whether a block should be ignored or not + * + */ +void block_parser_register_function (BlockParser *parser, const gchar *conditional_name, BlockParserConditionalFunction callback, gpointer user_data); + +/* * block_parser_get_data: return retrieved data or NULL if none read yet * returns newly allocated string, caller is responsible for freeing * diff --git a/src/replace-table.c b/src/replace-table.c index 3398bae..9c1b254 100644 --- a/src/replace-table.c +++ b/src/replace-table.c @@ -209,38 +209,64 @@ parse_function_args (const char *str, GPtrArray *a) add_arg (a, str_start, str + i - str_start); } -static gboolean -parse_registered_function (const char *token, gchar **out_fname, gchar ***args) +/* + * parse_function: returns name of the function or NULL if token is invalid. Parsed arguments are stored in *args. + * - in case an exclamation mark is present before the function name, the *negation argument is set to TRUE + * + */ +gchar * +parse_function (const char *token, gchar ***args, gboolean *negation) { char *opening_p, *closing_p; GPtrArray *a; + gchar *tok; gchar *s; + gchar *fname; - g_return_val_if_fail (token != NULL, FALSE); - g_return_val_if_fail (out_fname != NULL, FALSE); + if (args) + *args = NULL; + if (negation) + *negation = FALSE; - opening_p = strchr (token, '('); - closing_p = strchr (token, ')'); + g_return_val_if_fail (token != NULL, NULL); + + tok = g_strdup (token); + g_strstrip (tok); + opening_p = strchr (tok, '('); + closing_p = strrchr (tok, ')'); /* every function call should contain an opening and closing parenthesis */ - if (opening_p == NULL || closing_p == NULL || closing_p <= opening_p) - return FALSE; + if (opening_p == NULL || closing_p == NULL || closing_p <= opening_p) { + g_free (tok); + return NULL; + } + + /* find a possible exclamation mark */ + if (*tok == '!') { + if (negation) + *negation = TRUE; + *tok = ' '; + } /* find function name */ - s = g_strndup (token, opening_p - token); - *out_fname = g_strdup (g_strstrip (s)); + s = g_strndup (tok, opening_p - tok); + fname = g_strdup (g_strstrip (s)); g_free (s); /* parse arguments */ - a = g_ptr_array_new (); - s = g_strndup (opening_p + 1, closing_p - opening_p - 1); - parse_function_args (s, a); - g_free (s); + if (args) { + a = g_ptr_array_new (); + s = g_strndup (opening_p + 1, closing_p - opening_p - 1); + parse_function_args (s, a); + g_free (s); - g_ptr_array_add (a, NULL); - *args = (gchar **) g_ptr_array_free (a, FALSE); + g_ptr_array_add (a, NULL); + *args = (gchar **) g_ptr_array_free (a, FALSE); + } + + g_free (tok); - return TRUE; + return fname; } /* @@ -289,15 +315,18 @@ replace_table_process (gchar **buffer, ReplaceTable *table) } /* check registered functions */ - if (! replace_value && parse_registered_function (token, &s, &args)) { - func_data = g_hash_table_lookup (table->functions, s); - g_free (s); - if (func_data) { - replace_value = func_data->callback (args, func_data->user_data); - if (replace_value == NULL) - replace_value = g_strdup (""); + if (! replace_value) { + s = parse_function (token, &args, NULL); + if (s) { + func_data = g_hash_table_lookup (table->functions, s); + if (func_data) { + replace_value = func_data->callback (args, func_data->user_data); + if (replace_value == NULL) + replace_value = g_strdup (""); + } + g_strfreev (args); + g_free (s); } - g_strfreev (args); } /* lookup in the replace table */ @@ -437,12 +466,12 @@ extract_token_arg (const gchar *str) const gchar *start; const gchar *end; - start = strstr (str, "("); + start = strchr (str, '('); if (start == NULL) return NULL; start++; - end = strstr (str, ")"); + end = strrchr (str, ')'); if (end == NULL) return NULL; end++; diff --git a/src/replace-table.h b/src/replace-table.h index 81365cc..1a1c4ac 100644 --- a/src/replace-table.h +++ b/src/replace-table.h @@ -100,6 +100,13 @@ gchar * extract_token_arg (const gchar *str); */ gboolean token_has_prefix (const gchar *token, const gchar *prefix); +/* + * parse_function: returns name of the function or NULL if token is invalid. Parsed arguments are stored in *args. + * - in case an exclamation mark is present before the function name, the *negation argument is set to TRUE + * + */ +gchar * parse_function (const char *token, gchar ***args, gboolean *negation); + G_END_DECLS |
