changeset 3292:a97fb19a0148 trunk

Add support for functions.
author William Pitcock <nenolod@atheme-project.org>
date Thu, 09 Aug 2007 10:29:45 -0500
parents 02335e399a16
children 910c9296d6b3 6600abe94a3f d1b43bf0e67d
files src/audacious/tuple_formatter.c src/audacious/tuple_formatter.h src/tests/tuple_formatter_functor_test.c
diffstat 3 files changed, 158 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/src/audacious/tuple_formatter.c	Thu Aug 09 09:38:21 2007 -0500
+++ b/src/audacious/tuple_formatter.c	Thu Aug 09 10:29:45 2007 -0500
@@ -21,6 +21,7 @@
 #include <glib.h>
 #include <mowgli.h>
 
+#include "config.h"
 #include "tuple.h"
 #include "tuple_formatter.h"
 
@@ -44,9 +45,10 @@
  *   - ${==field,field:expr}: evaluates expr if both fields are the same
  *   - ${!=field,field:expr}: evaluates expr if both fields are not the same
  *   - ${(empty)?field:expr}: evaluates expr if field is empty or does not exist
+ *   - %{function:args,arg2,...}: runs function and inserts the result.
  *
  * everything else is treated as raw text.
- * additionally, plugins can add additional instructions!
+ * additionally, plugins can add additional instructions and functions!
  */
 
 typedef struct {
@@ -73,9 +75,9 @@
     for (iter = string; *iter != '\0'; iter++)
     {
         /* if it's raw text, just copy the byte */
-        if (*iter != '$')
+        if (*iter != '$' && *iter != '%')
             g_string_append_c(ctx->str, *iter);
-        else if (*(iter + 1) == '{')
+        else if (*iter == '$' && *(iter + 1) == '{')
         {
             GString *expression = g_string_new("");
             GString *argument = g_string_new("");
@@ -91,7 +93,7 @@
                     continue;
                 }
 
-                if (g_str_has_prefix(iter, "${") == TRUE)
+                if (g_str_has_prefix(iter, "${") == TRUE || g_str_has_prefix(iter, "%{") == TRUE)
                 {
                     if (sel == argument)
                     {
@@ -131,6 +133,62 @@
             if (*iter == '\0')
                 break;
         }
+        else if (*iter == '%' && *(iter + 1) == '{')
+        {
+            GString *expression = g_string_new("");
+            GString *argument = g_string_new("");
+            GString *sel = expression;
+            gchar *result;
+            gint level = 0;
+
+            for (iter += 2; *iter != '\0'; iter++)
+            {
+                if (*iter == ':')
+                {
+                    sel = argument;
+                    continue;
+                }
+
+                if (g_str_has_prefix(iter, "${") == TRUE || g_str_has_prefix(iter, "%{") == TRUE)
+                {
+                    if (sel == argument)
+                    {
+                        g_string_append_c(sel, *iter);
+                        level++;
+                    }
+                }
+                else if (*iter == '}' && (sel == argument && --level > 0))
+                    g_string_append_c(sel, *iter);
+                else if (*iter == '}' && ((sel != argument) || (sel == argument && level <= 0)))
+                {
+                    if (sel == argument)
+                        iter++;
+                    break;
+                }
+                else
+                    g_string_append_c(sel, *iter);
+            }
+
+            if (expression->len == 0)
+            {
+                g_string_free(expression, TRUE);
+                g_string_free(argument, TRUE);
+                continue;
+            }
+
+            result = tuple_formatter_process_function(tuple, expression->str, argument->len ? argument->str : NULL);
+            if (result != NULL)
+            {
+                g_string_append(ctx->str, result);
+                g_free(result);
+            }
+
+            g_string_free(expression, TRUE);
+            g_string_free(argument, TRUE);
+
+            if (*iter == '\0')
+                break;
+        }
     }
 
     out = g_strdup(ctx->str->str);
@@ -196,6 +254,56 @@
     return NULL;
 }
 
+static GList *tuple_formatter_func_list = NULL;
+
+typedef struct {
+    const gchar *name;
+    gchar *(*func)(Tuple *tuple, gchar **args);
+} TupleFormatterFunction;
+
+/* processes a function */
+gchar *
+tuple_formatter_process_function(Tuple *tuple, const gchar *expression, 
+    const gchar *argument)
+{
+    TupleFormatterFunction *expr = NULL;
+    GList *iter;
+
+    g_return_val_if_fail(tuple != NULL, NULL);
+    g_return_val_if_fail(expression != NULL, NULL);
+
+    for (iter = tuple_formatter_func_list; iter != NULL; iter = iter->next)
+    {
+        TupleFormatterFunction *tmp = (TupleFormatterFunction *) iter->data;
+
+        if (g_str_has_prefix(expression, tmp->name) == TRUE)
+        {
+            expr = tmp;
+            expression += strlen(tmp->name);
+        }
+    }
+
+    if (expr != NULL)
+    {
+        gchar **args;
+        gchar *ret;
+
+        if (argument)
+            args = g_strsplit(argument, ",", 10);
+        else
+            args = NULL;
+
+        ret = expr->func(tuple, args);
+
+        if (args)
+            g_strfreev(args);
+
+        return ret;
+    }
+
+    return NULL;
+}
+
 /* registers a formatter */
 void
 tuple_formatter_register_expression(const gchar *keyword,
@@ -213,6 +321,23 @@
     tuple_formatter_expr_list = g_list_append(tuple_formatter_expr_list, expr);
 }
 
+/* registers a function */
+void
+tuple_formatter_register_function(const gchar *keyword,
+	gchar *(*func)(Tuple *tuple, gchar **argument))
+{
+    TupleFormatterFunction *expr;
+
+    g_return_if_fail(keyword != NULL);
+    g_return_if_fail(func != NULL);
+
+    expr = g_new0(TupleFormatterFunction, 1);
+    expr->name = keyword;
+    expr->func = func;
+
+    tuple_formatter_func_list = g_list_append(tuple_formatter_func_list, expr);
+}
+
 /* builtin-keyword: ${?arg}, returns TRUE if <arg> exists. */
 static gboolean
 tuple_formatter_expression_exists(Tuple *tuple, const gchar *expression)
@@ -292,6 +417,13 @@
     return ret;
 }
 
+/* builtin function: %{audacious-version} */
+static gchar *
+tuple_formatter_function_version(Tuple *tuple, gchar **args)
+{
+    return g_strdup(PACKAGE_NAME " " PACKAGE_VERSION);
+}
+
 /* processes a string containing instructions. does initialization phases
    if not already done */
 gchar *
@@ -305,6 +437,8 @@
         tuple_formatter_register_expression("==", tuple_formatter_expression_match);
         tuple_formatter_register_expression("!=", tuple_formatter_expression_nonmatch);
         tuple_formatter_register_expression("(empty)?", tuple_formatter_expression_empty);
+
+        tuple_formatter_register_function("audacious-version", tuple_formatter_function_version);
         initialized = TRUE;
     }
 
--- a/src/audacious/tuple_formatter.h	Thu Aug 09 09:38:21 2007 -0500
+++ b/src/audacious/tuple_formatter.h	Thu Aug 09 10:29:45 2007 -0500
@@ -29,8 +29,12 @@
 gchar *tuple_formatter_process_string(Tuple *tuple, const gchar *string);
 void tuple_formatter_register_expression(const gchar *keyword,
         gboolean (*func)(Tuple *tuple, const gchar *argument));
+void tuple_formatter_register_function(const gchar *keyword,
+        gchar *(*func)(Tuple *tuple, gchar **argument));
 gchar *tuple_formatter_process_expr(Tuple *tuple, const gchar *expression,
     const gchar *argument);
+gchar *tuple_formatter_process_function(Tuple *tuple, const gchar *expression,
+    const gchar *argument);
 gchar *tuple_formatter_process_construct(Tuple *tuple, const gchar *string);
 
 #endif
--- a/src/tests/tuple_formatter_functor_test.c	Thu Aug 09 09:38:21 2007 -0500
+++ b/src/tests/tuple_formatter_functor_test.c	Thu Aug 09 10:29:45 2007 -0500
@@ -49,6 +49,22 @@
     }
     g_free(tstr);
 
+    tstr = tuple_formatter_process_string(tuple, "%{audacious-version}");
+    if (g_str_has_prefix(tstr, "audacious") == FALSE)
+    {
+        g_print("fail 2: '%s'\n", tstr);
+        return EXIT_FAILURE;
+    }
+    g_free(tstr);
+
+    tstr = tuple_formatter_process_string(tuple, "${(true):%{audacious-version}}");
+    if (g_str_has_prefix(tstr, "audacious") == FALSE)
+    {
+        g_print("fail 3: '%s'\n", tstr);
+        return EXIT_FAILURE;
+    }
+    g_free(tstr);
+
     mowgli_object_unref(tuple);
 
     return EXIT_SUCCESS;