summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/replace-table.c148
-rw-r--r--src/replace-table.h11
2 files changed, 159 insertions, 0 deletions
diff --git a/src/replace-table.c b/src/replace-table.c
index 3e4f2b0..2f80beb 100644
--- a/src/replace-table.c
+++ b/src/replace-table.c
@@ -33,8 +33,14 @@
struct ReplaceTable {
GHashTable *table;
GHashTable *defines;
+ GHashTable *functions;
};
+typedef struct {
+ ReplaceTableFunction callback;
+ gpointer user_data;
+} RegisteredFuncData;
+
ReplaceTable *
replace_table_new ()
@@ -43,6 +49,7 @@ replace_table_new ()
table = g_new0 (ReplaceTable, 1);
table->table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+ table->functions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
return table;
}
@@ -53,6 +60,7 @@ replace_table_free (ReplaceTable *table)
g_return_if_fail (table != NULL);
g_hash_table_destroy (table->table);
+ g_hash_table_destroy (table->functions);
g_free (table);
}
@@ -110,6 +118,132 @@ replace_table_set_defines (ReplaceTable *table, GHashTable *defines)
}
/*
+ * replace_table_register_function: register a method callback for specified function name
+ *
+ */
+void
+replace_table_register_function (ReplaceTable *table, const gchar *function_name, ReplaceTableFunction callback, gpointer user_data)
+{
+ RegisteredFuncData *func_data;
+
+ g_return_if_fail (table != NULL);
+
+ func_data = g_malloc0 (sizeof (RegisteredFuncData));
+ func_data->callback = callback;
+ func_data->user_data = user_data;
+
+ g_hash_table_insert (table->functions, g_strdup (function_name), func_data);
+}
+
+static void
+add_arg (GPtrArray *table, const char *str, gsize n)
+{
+ char *s;
+ char *s2;
+
+ if (n > 0) {
+ s = g_strndup (str, n);
+ s2 = g_strstrip (s);
+ if (strlen (s2) > 0)
+ g_ptr_array_add (table, g_strdup (s2));
+ g_free (s);
+ }
+}
+
+static void
+parse_function_args (const char *str, GPtrArray *a)
+{
+ gboolean in_quotes;
+ gboolean in_apos;
+ int i;
+ const char *str_start;
+
+ in_quotes = FALSE;
+ in_apos = FALSE;
+ str_start = str;
+
+ for (i = 0; i < strlen (str); i++) {
+ switch (str[i]) {
+ case '"':
+ if (in_apos || (i > 0 && str[i - 1] == '\\'))
+ continue;
+
+ in_quotes = ! in_quotes;
+ if (in_quotes) {
+ str_start = str + i + 1;
+ }
+ else {
+ add_arg (a, str_start, str + i - str_start);
+ str_start = NULL;
+ }
+ break;
+ case '\'':
+ if (in_quotes || (i > 0 && str[i - 1] == '\\'))
+ continue;
+
+ in_apos = ! in_apos;
+ if (in_apos) {
+ str_start = str + i + 1;
+ }
+ else {
+ add_arg (a, str_start, str + i - str_start);
+ str_start = NULL;
+ }
+ break;
+ case ',':
+ if (! in_quotes && ! in_apos && str_start) {
+ add_arg (a, str_start, str + i - str_start);
+ str_start = str + i + 1;
+ }
+ break;
+ }
+ }
+
+ if (in_quotes)
+ g_print ("Error: argument string \"%s\" is missing a closing quote\n", str);
+ else
+ if (in_apos)
+ g_print ("Error: argument string \"%s\" is missing a closing apostrophe\n", str);
+ else
+ if (str_start != NULL)
+ add_arg (a, str_start, str + i - str_start);
+}
+
+static gboolean
+parse_registered_function (const char *token, gchar **out_fname, gchar ***args)
+{
+ char *opening_p, *closing_p;
+ GPtrArray *a;
+ gchar *s;
+
+ g_return_val_if_fail (token != NULL, FALSE);
+ g_return_val_if_fail (out_fname != NULL, FALSE);
+
+ opening_p = strchr (token, '(');
+ closing_p = strchr (token, ')');
+
+ /* every function call should contain an opening and closing parenthesis */
+ if (opening_p == NULL || closing_p == NULL || closing_p <= opening_p)
+ return FALSE;
+
+ /* find function name */
+ s = g_strndup (token, opening_p - token);
+ *out_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);
+
+ g_ptr_array_add (a, NULL);
+ *args = (gchar **) g_ptr_array_free (a, FALSE);
+
+ return TRUE;
+}
+
+/*
* replace_table_process: process buffer and replace all tags filled in the replace table
*
* - reallocates source buffer
@@ -126,6 +260,8 @@ replace_table_process (gchar **buffer, ReplaceTable *table)
GString *dst;
gboolean tag_parameter;
gboolean handled;
+ gchar **args;
+ RegisteredFuncData *func_data;
g_return_if_fail (table != NULL);
g_return_if_fail (buffer != NULL);
@@ -152,6 +288,18 @@ replace_table_process (gchar **buffer, ReplaceTable *table)
g_free (s);
}
+ /* 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 ("");
+ }
+ g_strfreev (args);
+ }
+
/* lookup in the replace table */
if (! replace_value)
replace_value = g_strdup (g_hash_table_lookup (table->table, token));
diff --git a/src/replace-table.h b/src/replace-table.h
index 7d6b70e..0d81c92 100644
--- a/src/replace-table.h
+++ b/src/replace-table.h
@@ -25,6 +25,11 @@ G_BEGIN_DECLS
typedef struct ReplaceTable ReplaceTable;
+/*
+ * registered function callback, arguments passed as strings
+ */
+typedef char * (*ReplaceTableFunction) (gchar **args, gpointer user_data);
+
ReplaceTable * replace_table_new ();
@@ -48,6 +53,12 @@ void replace_table_add_key_printf (ReplaceTable *table, const gchar *tag, const
void replace_table_set_defines (ReplaceTable *table, GHashTable *defines);
/*
+ * replace_table_register_function: register a method callback for specified function name
+ *
+ */
+void replace_table_register_function (ReplaceTable *table, const gchar *function_name, ReplaceTableFunction callback, gpointer user_data);
+
+/*
* replace_table_process: process buffer and replace all tags filled in the replace table
*
* - reallocates source buffer