diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/replace-table.c | 148 | ||||
| -rw-r--r-- | src/replace-table.h | 11 |
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 |
