# HG changeset patch # User William Pitcock # Date 1186658367 18000 # Node ID 6062ef95818b22d3e54b73724220eb4a436a9479 # Parent b78d3197c70d4eb5fca43ad2656c52827c1d7275 Add first revision parser code. May or may not work, not hooked up, so I can't test it yet. ;) diff -r b78d3197c70d -r 6062ef95818b src/audacious/Makefile --- 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 \ diff -r b78d3197c70d -r 6062ef95818b src/audacious/tuple_formatter.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 . + * + * The Audacious team does not consider modular code linking to + * Audacious or using our public API to be a derived work. + */ + +#include +#include + +#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 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); +} diff -r b78d3197c70d -r 6062ef95818b src/audacious/tuple_formatter.h --- /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 . + * + * 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 +#include + +#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