summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomas Bzatek <tbzatek@users.sourceforge.net>2012-12-24 20:10:27 +0100
committerTomas Bzatek <tbzatek@users.sourceforge.net>2012-12-24 20:10:27 +0100
commitc5e75352f27a02501b3a1a9189f10a581c12e7fb (patch)
treeb3bdae02b91bbb7ab4f5bb48b9704dbf378ce533
parentdff418800174265b1a591ac44eb244e2b16f94a5 (diff)
downloadcataract-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.c57
-rw-r--r--src/block-parser.h11
-rw-r--r--src/replace-table.c83
-rw-r--r--src/replace-table.h7
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