changeset 3283:6062ef95818b trunk

Add first revision parser code. May or may not work, not hooked up, so I can't test it yet. ;)
author William Pitcock <nenolod@atheme-project.org>
date Thu, 09 Aug 2007 06:19:27 -0500
parents b78d3197c70d
children 70789a2a5a65
files src/audacious/Makefile src/audacious/tuple_formatter.c src/audacious/tuple_formatter.h
diffstat 3 files changed, 249 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/audacious/Makefile	Thu Aug 09 03:48:01 2007 -0500
+++ b/src/audacious/Makefile	Thu Aug 09 06:19:27 2007 -0500
@@ -98,6 +98,7 @@
 	strings.c \
 	titlestring.c \
 	tuple.c \
+	tuple_formatter.c \
 	skin.c \
 	ui_about.c \
 	ui_albumart.c \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/audacious/tuple_formatter.c	Thu Aug 09 06:19:27 2007 -0500
@@ -0,0 +1,212 @@
+/*
+ * Audacious
+ * Copyright (c) 2007 William Pitcock
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; under version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses>.
+ *
+ * The Audacious team does not consider modular code linking to
+ * Audacious or using our public API to be a derived work.
+ */
+
+#include <glib.h>
+#include <mowgli.h>
+
+#include "tuple.h"
+#include "tuple_formatter.h"
+
+/*
+ * the tuple formatter:
+ *
+ * this is a data-driven meta-language which eventually hopes to be
+ * turing complete.
+ *
+ * language constructs follow the following basic rules:
+ *   - begin with ${
+ *   - end with }
+ *
+ * language constructs:
+ *   - ${field}: prints a field
+ *   - ${?field:expr}: evaluates expr if field exists
+ *   - ${=field:"value"}: defines field in the currently iterated
+ *                        tuple as string value of "value"
+ *   - ${=field:value}: defines field in the currently iterated
+ *                      tuple as integer value of "value"
+ *   - ${==field,field:expr}: evaluates expr if both fields are the same
+ *   - ${!=field,field:expr}: evaluates expr if both fields are not the same
+ *
+ * everything else is treated as raw text.
+ */
+
+typedef struct {
+    Tuple *tuple;
+    GString str;
+} TupleFormatterContext;
+
+/* processes a construct, e.g. "${?artist:artist is defined}" would
+   return "artist is defined" if artist is defined. */
+gchar *
+tuple_formatter_process_construct(Tuple *tuple, const gchar *string)
+{
+    TupleFormatterContext *ctx;
+    const gchar *iter;
+    gchar *out;
+
+    g_return_val_if_fail(tuple != NULL, NULL);
+    g_return_val_if_fail(string != NULL, NULL);
+
+    ctx = g_new0(TupleFormatterContext, 1);
+
+    for (iter = string; *iter != '\0'; iter++)
+    {
+        /* if it's raw text, just copy the byte */
+        if (*iter != '$')
+            g_string_append_c(&ctx->str, *iter);
+        else if (*(iter + 1) == '{')
+        {
+            GString expression = {};
+            GString argument = {};
+            GString *sel = &expression;
+            gchar *result;
+
+            for (iter += 2; *iter != '\0'; iter++)
+            {
+                switch(*iter)
+                {
+                case '}':
+                    break;
+                case ':':
+                    sel = &argument;
+                    break;
+                default:
+                    g_string_append_c(sel, *iter);
+                    break;
+                }
+            }
+
+            if (expression.len == 0)
+                continue;
+
+            result = tuple_formatter_process_expr(tuple, expression.str, argument.len ? argument.str : NULL);
+            if (result != NULL)
+            {
+                g_string_append(&ctx->str, result);
+                g_free(result);
+            }
+
+            g_free(expression.str);
+            g_free(argument.str);
+        }
+    }
+
+    out = g_strdup(ctx->str.str);
+    g_free(ctx->str.str);
+    g_free(ctx);
+
+    return out;
+}
+
+static GList *tuple_formatter_expr_list = NULL;
+
+typedef struct {
+    const gchar *name;
+    gboolean (*func)(Tuple *tuple, const gchar *expression);
+} TupleFormatterExpression;
+
+/* processes an expression and optional argument pair. */
+gchar *
+tuple_formatter_process_expr(Tuple *tuple, const gchar *expression, 
+    const gchar *argument)
+{
+    TupleFormatterExpression *expr = NULL;
+    GList *iter;
+
+    g_return_val_if_fail(tuple != NULL, NULL);
+    g_return_val_if_fail(expression != NULL, NULL);
+
+    for (iter = tuple_formatter_expr_list; iter != NULL; iter = iter->next)
+    {
+        TupleFormatterExpression *tmp = (TupleFormatterExpression *) iter->data;
+
+        if (g_str_has_prefix(tmp->name, expression) == TRUE)
+        {
+            expr = tmp;
+            expression += strlen(tmp->name);
+        }
+    }
+
+    /* ${artist} */
+    if (expr == NULL && argument == NULL)
+    {
+        TupleValueType type = tuple_get_value_type(tuple, expression);
+
+        switch(type)
+        {
+        case TUPLE_STRING:
+             return g_strdup(tuple_get_string(tuple, expression));
+             break;
+        case TUPLE_INT:
+             return g_strdup_printf("%d", tuple_get_int(tuple, expression));
+             break;
+        case TUPLE_UNKNOWN:
+        default:
+             return NULL;
+        }
+    }
+    else if (expr != NULL)
+    {
+        if (expr->func(tuple, expression) == TRUE && argument != NULL)
+            return tuple_formatter_process_construct(tuple, argument);
+    }
+
+    return NULL;
+}
+
+/* registers a formatter */
+void
+tuple_formatter_register_expression(const gchar *keyword,
+	gboolean (*func)(Tuple *tuple, const gchar *argument))
+{
+    TupleFormatterExpression *expr;
+
+    g_return_if_fail(keyword != NULL);
+    g_return_if_fail(func != NULL);
+
+    expr = g_new0(TupleFormatterExpression, 1);
+    expr->name = keyword;
+    expr->func = func;
+
+    tuple_formatter_expr_list = g_list_append(tuple_formatter_expr_list, expr);
+}
+
+/* builtin-keyword: ${?arg}, returns TRUE if <arg> exists. */
+static gboolean
+tuple_formatter_expression_exists(Tuple *tuple, const gchar *expression)
+{
+    return (tuple_get_value_type(tuple, expression) != TUPLE_UNKNOWN) ? TRUE : FALSE;
+}
+
+/* processes a string containing instructions. does initialization phases
+   if not already done */
+gchar *
+tuple_formatter_process_string(Tuple *tuple, const gchar *string)
+{
+    static gboolean initialized = FALSE;
+
+    if (initialized == FALSE)
+    {
+        tuple_formatter_register_expression("?", tuple_formatter_expression_exists);
+        initialized = TRUE;
+    }
+
+    return tuple_formatter_process_string(tuple, string);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/audacious/tuple_formatter.h	Thu Aug 09 06:19:27 2007 -0500
@@ -0,0 +1,36 @@
+/*
+ * Audacious
+ * Copyright (c) 2007 William Pitcock
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; under version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses>.
+ *
+ * The Audacious team does not consider modular code linking to
+ * Audacious or using our public API to be a derived work.
+ */
+
+#ifndef __AUDACIOUS_TUPLE_FORMATTER_H__
+#define __AUDACIOUS_TUPLE_FORMATTER_H__
+
+#include <glib.h>
+#include <mowgli.h>
+
+#include "tuple.h"
+
+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));
+gchar *tuple_formatter_process_expr(Tuple *tuple, const gchar *expression,
+    const gchar *argument);
+gchar *tuple_formatter_process_construct(Tuple *tuple, const gchar *string);
+
+#endif