changeset 3285:740c6f845554 trunk

revise tuple formatting engine logic
author William Pitcock <nenolod@atheme-project.org>
date Thu, 09 Aug 2007 08:22:08 -0500
parents 70789a2a5a65
children 8576de468e23
files src/audacious/tuple_formatter.c src/tests/Makefile src/tests/test_harness.c src/tests/tuple_formatter_test.c
diffstat 4 files changed, 174 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/src/audacious/tuple_formatter.c	Thu Aug 09 06:21:09 2007 -0500
+++ b/src/audacious/tuple_formatter.c	Thu Aug 09 08:22:08 2007 -0500
@@ -50,7 +50,7 @@
 
 typedef struct {
     Tuple *tuple;
-    GString str;
+    GString *str;
 } TupleFormatterContext;
 
 /* processes a construct, e.g. "${?artist:artist is defined}" would
@@ -66,51 +66,74 @@
     g_return_val_if_fail(string != NULL, NULL);
 
     ctx = g_new0(TupleFormatterContext, 1);
+    ctx->str = g_string_new("");
 
+    /* parsers are ugly */
     for (iter = string; *iter != '\0'; iter++)
     {
         /* if it's raw text, just copy the byte */
         if (*iter != '$')
-            g_string_append_c(&ctx->str, *iter);
+            g_string_append_c(ctx->str, *iter);
         else if (*(iter + 1) == '{')
         {
-            GString expression = {};
-            GString argument = {};
-            GString *sel = &expression;
+            GString *expression = g_string_new("");
+            GString *argument = g_string_new("");
+            GString *sel = expression;
             gchar *result;
+            gint level = 0;
 
             for (iter += 2; *iter != '\0'; iter++)
             {
-                switch(*iter)
+                if (*iter == ':')
+                {
+                    sel = argument;
+                    continue;
+                }
+
+                if (g_str_has_prefix(iter, "${") == TRUE)
                 {
-                case '}':
-                    break;
-                case ':':
-                    sel = &argument;
-                    break;
-                default:
+                    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)
+            if (expression->len == 0)
+            {
+                g_string_free(expression, TRUE);
+                g_string_free(argument, TRUE);
                 continue;
+            }
 
-            result = tuple_formatter_process_expr(tuple, expression.str, argument.len ? argument.str : NULL);
+            result = tuple_formatter_process_expr(tuple, expression->str, argument->len ? argument->str : NULL);
             if (result != NULL)
             {
-                g_string_append(&ctx->str, result);
+                g_string_append(ctx->str, result);
                 g_free(result);
             }
 
-            g_free(expression.str);
-            g_free(argument.str);
+            g_string_free(expression, TRUE);
+            g_string_free(argument, TRUE);
+
+            if (*iter == '\0')
+                break;
         }
     }
 
-    out = g_strdup(ctx->str.str);
-    g_free(ctx->str.str);
+    out = g_strdup(ctx->str->str);
+    g_string_free(ctx->str, TRUE);
     g_free(ctx);
 
     return out;
@@ -138,7 +161,7 @@
     {
         TupleFormatterExpression *tmp = (TupleFormatterExpression *) iter->data;
 
-        if (g_str_has_prefix(tmp->name, expression) == TRUE)
+        if (g_str_has_prefix(expression, tmp->name) == TRUE)
         {
             expr = tmp;
             expression += strlen(tmp->name);
@@ -209,5 +232,5 @@
         initialized = TRUE;
     }
 
-    return tuple_formatter_process_string(tuple, string);
+    return tuple_formatter_process_construct(tuple, string);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/Makefile	Thu Aug 09 08:22:08 2007 -0500
@@ -0,0 +1,30 @@
+include ../../mk/rules.mk
+include ../../mk/init.mk
+include ../../mk/objective.mk
+
+OBJECTIVE_LIBS_NOINST = tuple_formatter_test
+
+LDFLAGS += $(AUDLDFLAGS)
+LDADD = \
+	$(DBUS_LIBS) \
+	$(GTK_LIBS)      \
+	$(MOWGLI_LIBS)	 \
+	$(LIBGLADE_LIBS)
+
+CFLAGS += \
+	$(GTK_CFLAGS)      \
+	$(DBUS_CFLAGS)     \
+	$(LIBGLADE_CFLAGS) \
+	$(BEEP_DEFINES)    \
+	$(ARCH_DEFINES)    \
+	$(MOWGLI_CFLAGS)   \
+	-I.. -I../..   \
+	-I../intl -I../audacious
+
+COMMON_OBJS = test_harness.o
+TFT_OBJS = $(COMMON_OBJS) tuple_formatter_test.o ../audacious/tuple.o ../audacious/tuple_formatter.o
+tuple_formatter_test: $(TFT_OBJS)
+	$(CC) $(LDFLAGS) $(TFT_OBJS) $(LDADD) -o $@
+	@printf "%10s     %-20s\n" LINK $@
+	./$@
+	@printf "%10s     %-20s\n" TEST-PASS $@
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/test_harness.c	Thu Aug 09 08:22:08 2007 -0500
@@ -0,0 +1,38 @@
+/*
+ * 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>
+
+extern int test_run(gint argc, const gchar *argv[]);
+
+int
+main(gint argc, const gchar *argv[])
+{
+    g_thread_init(NULL);
+
+    mowgli_init();
+
+    if (!g_thread_supported())
+        mowgli_log("Warning: GThread not supported. Some tests may fail.");
+
+    return test_run(argc, argv);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/tests/tuple_formatter_test.c	Thu Aug 09 08:22:08 2007 -0500
@@ -0,0 +1,62 @@
+/*
+ * 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"
+
+int
+test_run(int argc, const char *argv[])
+{
+    Tuple *tuple;
+    gchar *tstr;
+
+    tuple = tuple_new();
+    tuple_associate_string(tuple, "splork", "moo");
+    tuple_associate_int(tuple, "splorkerz", 42);
+
+    tstr = tuple_formatter_process_string(tuple, "${splork} ${splorkerz}");
+    if (g_ascii_strcasecmp(tstr, "moo 42"))
+    {
+        g_print("fail 1: '%s'\n", tstr);
+        return EXIT_FAILURE;
+    }
+    g_free(tstr);
+
+    tstr = tuple_formatter_process_string(tuple, "${?fizz:${splork}} ${splorkerz}");
+    if (g_ascii_strcasecmp(tstr, " 42"))
+    {
+        g_print("fail 2: '%s'\n", tstr);
+        return EXIT_FAILURE;
+    }
+    g_free(tstr);
+
+    tstr = tuple_formatter_process_string(tuple, "${?splork:${splork}} ${splorkerz}");
+    if (g_ascii_strcasecmp(tstr, "moo 42"))
+    {
+        g_print("fail 3: '%s'\n", tstr);
+        return EXIT_FAILURE;
+    }
+    g_free(tstr);
+
+    return EXIT_SUCCESS;
+}