00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <glib.h>
00022 #include <mowgli.h>
00023
00024 #include "config.h"
00025 #include "tuple.h"
00026 #include "tuple_formatter.h"
00027 #include "audstrings.h"
00028
00029
00030
00031
00032
00033
00034 #define TUPLE_USE_COMPILER
00035
00036
00037
00038
00039
00040
00041 #undef TUPLE_COMPILER_DEBUG
00042
00043 #ifdef TUPLE_USE_COMPILER
00044 # include "tuple_compiler.h"
00045 static GStaticMutex tuplec_mutex = G_STATIC_MUTEX_INIT;
00046 #endif
00047
00048 #ifdef _DEBUG
00049 # define _TRACE(fmt, ...) g_print("[tuple-fmt] %s(%d) " fmt "\n", __FILE__, __LINE__, __VA_ARGS__);
00050 #else
00051 # define _TRACE(fmt, ...)
00052 #endif
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080 typedef struct {
00081 Tuple *tuple;
00082 GString *str;
00083 } TupleFormatterContext;
00084
00085
00086
00087 gchar *
00088 tuple_formatter_process_construct(Tuple *tuple, const gchar *string)
00089 {
00090 TupleFormatterContext *ctx;
00091 const gchar *iter;
00092 gchar *out;
00093 gint level = 0;
00094
00095 g_return_val_if_fail(tuple != NULL, NULL);
00096 g_return_val_if_fail(string != NULL, NULL);
00097
00098 ctx = g_new0(TupleFormatterContext, 1);
00099 ctx->str = g_string_new("");
00100
00101 _TRACE("parsing <%s>", string);
00102
00103
00104 for (iter = string; *iter != '\0'; iter++)
00105 {
00106
00107 if (*iter != '$' && *iter != '%' && *iter != '}' )
00108 {
00109 g_string_append_c(ctx->str, *iter);
00110 }
00111 else if (*iter == '}' && level > 0)
00112 {
00113 level--;
00114 }
00115 else if (g_str_has_prefix(iter, "${") == TRUE)
00116 {
00117 GString *expression = g_string_new("");
00118 GString *argument = g_string_new("");
00119 GString *sel = expression;
00120 gchar *result;
00121 level++;
00122
00123 for (iter += 2; *iter != '\0'; iter++)
00124 {
00125 if (*iter == ':')
00126 {
00127 if (sel != argument)
00128 {
00129 sel = argument;
00130 continue;
00131 }
00132 else
00133 g_string_append_c(sel, *iter);
00134 continue;
00135 }
00136
00137 if (g_str_has_prefix(iter, "${") == TRUE || g_str_has_prefix(iter, "%{") == TRUE)
00138 {
00139 if (sel == argument)
00140 {
00141 g_string_append_c(sel, *iter);
00142 level++;
00143 }
00144 }
00145 else if (*iter == '}')
00146 {
00147 level--;
00148 if (sel == argument)
00149 {
00150 if (level == 0)
00151 break;
00152 else
00153 g_string_append_c(sel, *iter);
00154 }
00155 else
00156 break;
00157 }
00158 else
00159 g_string_append_c(sel, *iter);
00160 }
00161
00162 if (expression->len == 0)
00163 {
00164 g_string_free(expression, TRUE);
00165 g_string_free(argument, TRUE);
00166 continue;
00167 }
00168
00169 result = tuple_formatter_process_expr(tuple, expression->str, argument->len ? argument->str : NULL);
00170 if (result != NULL)
00171 {
00172 g_string_append(ctx->str, result);
00173 g_free(result);
00174 }
00175
00176 g_string_free(expression, TRUE);
00177 g_string_free(argument, TRUE);
00178
00179 if (*iter == '\0')
00180 break;
00181 }
00182 else if (g_str_has_prefix(iter, "%{") == TRUE)
00183 {
00184 GString *expression = g_string_new("");
00185 GString *argument = g_string_new("");
00186 GString *sel = expression;
00187 gchar *result;
00188 level++;
00189
00190 for (iter += 2; *iter != '\0'; iter++)
00191 {
00192 if (*iter == ':')
00193 {
00194 if (sel != argument)
00195 {
00196 sel = argument;
00197 continue;
00198 }
00199 else
00200 g_string_append_c(sel, *iter);
00201 continue;
00202 }
00203
00204 if (g_str_has_prefix(iter, "${") == TRUE || g_str_has_prefix(iter, "%{") == TRUE)
00205 {
00206 if (sel == argument)
00207 {
00208 g_string_append_c(sel, *iter);
00209 level++;
00210 }
00211 }
00212 else if (*iter == '}')
00213 {
00214 level--;
00215 if (sel == argument)
00216 {
00217 if (level == 0)
00218 break;
00219 else
00220 g_string_append_c(sel, *iter);
00221 }
00222 else
00223 break;
00224 }
00225 else
00226 g_string_append_c(sel, *iter);
00227 }
00228
00229 if (expression->len == 0)
00230 {
00231 g_string_free(expression, TRUE);
00232 g_string_free(argument, TRUE);
00233 continue;
00234 }
00235
00236 result = tuple_formatter_process_function(tuple, expression->str, argument->len ? argument->str : NULL);
00237 if (result != NULL)
00238 {
00239 g_string_append(ctx->str, result);
00240 g_free(result);
00241 }
00242
00243 g_string_free(expression, TRUE);
00244 g_string_free(argument, TRUE);
00245
00246 if (*iter == '\0')
00247 break;
00248 }
00249 }
00250
00251 out = g_strdup(ctx->str->str);
00252 g_string_free(ctx->str, TRUE);
00253 g_free(ctx);
00254
00255 _TRACE("parsed <%s> as <%s>", string, out);
00256
00257 return out;
00258 }
00259
00260 static GList *tuple_formatter_expr_list = NULL;
00261
00262 typedef struct {
00263 const gchar *name;
00264 gboolean (*func)(Tuple *tuple, const gchar *expression);
00265 } TupleFormatterExpression;
00266
00267
00268 gchar *
00269 tuple_formatter_process_expr(Tuple *tuple, const gchar *expression,
00270 const gchar *argument)
00271 {
00272 TupleFormatterExpression *expr = NULL;
00273 GList *iter;
00274
00275 g_return_val_if_fail(tuple != NULL, NULL);
00276 g_return_val_if_fail(expression != NULL, NULL);
00277
00278 for (iter = tuple_formatter_expr_list; iter != NULL; iter = iter->next)
00279 {
00280 TupleFormatterExpression *tmp = (TupleFormatterExpression *) iter->data;
00281
00282 if (g_str_has_prefix(expression, tmp->name) == TRUE)
00283 {
00284 expr = tmp;
00285 expression += strlen(tmp->name);
00286 }
00287 }
00288
00289
00290 if (expr == NULL && argument == NULL)
00291 {
00292 TupleValueType type = tuple_get_value_type(tuple, -1, expression);
00293
00294 switch(type)
00295 {
00296 case TUPLE_STRING:
00297 return g_strdup(tuple_get_string(tuple, -1, expression));
00298 break;
00299 case TUPLE_INT:
00300 return g_strdup_printf("%d", tuple_get_int(tuple, -1, expression));
00301 break;
00302 case TUPLE_UNKNOWN:
00303 default:
00304 return NULL;
00305 }
00306 }
00307 else if (expr != NULL)
00308 {
00309 if (expr->func(tuple, expression) == TRUE && argument != NULL)
00310 return tuple_formatter_process_construct(tuple, argument);
00311 }
00312
00313 return NULL;
00314 }
00315
00316 static GList *tuple_formatter_func_list = NULL;
00317
00318 typedef struct {
00319 const gchar *name;
00320 gchar *(*func)(Tuple *tuple, gchar **args);
00321 } TupleFormatterFunction;
00322
00323
00324 gchar *
00325 tuple_formatter_process_function(Tuple *tuple, const gchar *expression,
00326 const gchar *argument)
00327 {
00328 TupleFormatterFunction *expr = NULL;
00329 GList *iter;
00330
00331 g_return_val_if_fail(tuple != NULL, NULL);
00332 g_return_val_if_fail(expression != NULL, NULL);
00333
00334 for (iter = tuple_formatter_func_list; iter != NULL; iter = iter->next)
00335 {
00336 TupleFormatterFunction *tmp = (TupleFormatterFunction *) iter->data;
00337
00338 if (g_str_has_prefix(expression, tmp->name) == TRUE)
00339 {
00340 expr = tmp;
00341 expression += strlen(tmp->name);
00342 }
00343 }
00344
00345 if (expr != NULL)
00346 {
00347 gchar **args;
00348 gchar *ret;
00349
00350 if (argument)
00351 args = g_strsplit(argument, ",", 10);
00352 else
00353 args = NULL;
00354
00355 ret = expr->func(tuple, args);
00356
00357 if (args)
00358 g_strfreev(args);
00359
00360 return ret;
00361 }
00362
00363 return NULL;
00364 }
00365
00366
00367 void
00368 tuple_formatter_register_expression(const gchar *keyword,
00369 gboolean (*func)(Tuple *tuple, const gchar *argument))
00370 {
00371 TupleFormatterExpression *expr;
00372
00373 g_return_if_fail(keyword != NULL);
00374 g_return_if_fail(func != NULL);
00375
00376 expr = g_new0(TupleFormatterExpression, 1);
00377 expr->name = keyword;
00378 expr->func = func;
00379
00380 tuple_formatter_expr_list = g_list_append(tuple_formatter_expr_list, expr);
00381 }
00382
00383
00384 void
00385 tuple_formatter_register_function(const gchar *keyword,
00386 gchar *(*func)(Tuple *tuple, gchar **argument))
00387 {
00388 TupleFormatterFunction *expr;
00389
00390 g_return_if_fail(keyword != NULL);
00391 g_return_if_fail(func != NULL);
00392
00393 expr = g_new0(TupleFormatterFunction, 1);
00394 expr->name = keyword;
00395 expr->func = func;
00396
00397 tuple_formatter_func_list = g_list_append(tuple_formatter_func_list, expr);
00398 }
00399
00400
00401
00402 static gboolean
00403 tuple_formatter_expression_match(Tuple *tuple, const gchar *expression)
00404 {
00405 gchar **args = g_strsplit(expression, ",", 2);
00406 gchar *arg1 = NULL, *arg2 = NULL;
00407 gint ret;
00408
00409 if (args[0][0] == '\"')
00410 {
00411 if ( strlen(args[0]) > 1 )
00412 {
00413 args[0][strlen(args[0]) - 1] = '\0';
00414 arg1 = g_strdup(&(args[0][1]));
00415 args[0][strlen(args[0]) - 1] = '\"';
00416 }
00417 else
00418 return FALSE;
00419 }
00420 else if (tuple_get_value_type(tuple, -1, args[0]) == TUPLE_UNKNOWN)
00421 {
00422 g_strfreev(args);
00423 return FALSE;
00424 }
00425
00426 if (args[1][0] == '\"')
00427 {
00428 if ( strlen(args[1]) > 1 )
00429 {
00430 args[1][strlen(args[1]) - 1] = '\0';
00431 arg2 = g_strdup(&(args[1][1]));
00432 args[1][strlen(args[1]) - 1] = '\"';
00433 }
00434 else
00435 return FALSE;
00436 }
00437 else if (tuple_get_value_type(tuple, -1, args[1]) == TUPLE_UNKNOWN)
00438 {
00439 g_strfreev(args);
00440 return FALSE;
00441 }
00442
00443 if (!arg1)
00444 {
00445 if (tuple_get_value_type(tuple, -1, args[0]) == TUPLE_STRING)
00446 arg1 = g_strdup(tuple_get_string(tuple, -1, args[0]));
00447 else
00448 arg1 = g_strdup_printf("%d", tuple_get_int(tuple, -1, args[0]));
00449 }
00450
00451 if (!arg2)
00452 {
00453 if (tuple_get_value_type(tuple, -1, args[1]) == TUPLE_STRING)
00454 arg2 = g_strdup(tuple_get_string(tuple, -1, args[1]));
00455 else
00456 arg2 = g_strdup_printf("%d", tuple_get_int(tuple, -1, args[1]));
00457 }
00458
00459 ret = g_ascii_strcasecmp(arg1, arg2);
00460 g_free(arg1);
00461 g_free(arg2);
00462 g_strfreev(args);
00463
00464 return ret ? FALSE : TRUE;
00465 }
00466
00467
00468
00469 static gboolean
00470 tuple_formatter_expression_nonmatch(Tuple *tuple, const gchar *expression)
00471 {
00472 return tuple_formatter_expression_match(tuple, expression) ^ 1;
00473 }
00474
00475
00476 static gboolean
00477 tuple_formatter_expression_empty(Tuple *tuple, const gchar *expression)
00478 {
00479 gboolean ret = TRUE;
00480 const gchar *iter;
00481 TupleValueType type = tuple_get_value_type(tuple, -1, expression);
00482
00483 if (type == TUPLE_UNKNOWN)
00484 return TRUE;
00485
00486 if (type == TUPLE_INT)
00487 return (tuple_get_int(tuple, -1, expression) == 0);
00488
00489 iter = tuple_get_string(tuple, -1, expression);
00490 if (!iter)
00491 return TRUE;
00492
00493 while (ret && *iter != '\0')
00494 {
00495 if (*iter == ' ')
00496 iter++;
00497 else
00498 ret = FALSE;
00499 }
00500
00501 return ret;
00502 }
00503
00504
00505 static gboolean
00506 tuple_formatter_expression_exists(Tuple *tuple, const gchar *expression)
00507 {
00508 return !tuple_formatter_expression_empty(tuple, expression);
00509 }
00510
00511
00512 static gchar *
00513 tuple_formatter_function_version(Tuple *tuple, gchar **args)
00514 {
00515 return g_strdup(PACKAGE " " VERSION);
00516 }
00517
00518
00519
00520
00521
00522
00523
00524
00525 gchar * tuple_formatter_process_string (const Tuple * tuple, const gchar * string)
00526 {
00527 static gboolean initialized = FALSE;
00528 static gchar *last_string = NULL;
00529 #ifdef TUPLE_USE_COMPILER
00530 static TupleEvalContext *last_ctx = NULL;
00531 static TupleEvalNode *last_ev = NULL;
00532 gchar *result = NULL;
00533 #endif
00534
00535 if (initialized == FALSE)
00536 {
00537 tuple_formatter_register_expression("?", tuple_formatter_expression_exists);
00538 tuple_formatter_register_expression("==", tuple_formatter_expression_match);
00539 tuple_formatter_register_expression("!=", tuple_formatter_expression_nonmatch);
00540 tuple_formatter_register_expression("(empty)?", tuple_formatter_expression_empty);
00541
00542 tuple_formatter_register_function("audacious-version", tuple_formatter_function_version);
00543 initialized = TRUE;
00544 }
00545
00546 #ifdef TUPLE_USE_COMPILER
00547 g_static_mutex_lock (& tuplec_mutex);
00548
00549 if (last_string == NULL ||
00550 (last_string != NULL && strcmp(last_string, string)))
00551 {
00552 g_free(last_string);
00553
00554 if (last_ctx != NULL)
00555 {
00556 tuple_evalctx_free(last_ctx);
00557 tuple_evalnode_free(last_ev);
00558 }
00559
00560 last_ctx = tuple_evalctx_new();
00561 last_string = g_strdup(string);
00562 last_ev = tuple_formatter_compile(last_ctx, last_string);
00563 if (last_ctx->iserror) {
00564 g_warning("[TuplezCC]: %s", last_ctx->errmsg);
00565 }
00566 if (!last_ev) {
00567 g_warning("[TuplezCC]: Compilation failed!\n");
00568 }
00569 }
00570
00571 #ifdef TUPLE_COMPILER_DEBUG
00572 {
00573 gint level = 0;
00574
00575 tuple_formatter_print(stderr, &level, last_ctx, last_ev);
00576 }
00577 #endif
00578
00579 tuple_evalctx_reset(last_ctx);
00580
00581 result = tuple_formatter_eval(last_ctx, last_ev, tuple);
00582 if (last_ctx->iserror) {
00583 g_warning("[TuplezEV]: %s", last_ctx->errmsg);
00584 }
00585
00586 g_static_mutex_unlock (& tuplec_mutex);
00587
00588 return result;
00589 #else
00590 return tuple_formatter_process_construct(tuple, string);
00591 #endif
00592 }
00593
00594 gchar * tuple_formatter_make_title_string (const Tuple * tuple, const gchar *
00595 string)
00596 {
00597 gchar *title = tuple_formatter_process_string(tuple, string);
00598
00599 if (title == NULL || !title[0])
00600 {
00601 const char *filename = tuple_get_string(tuple, FIELD_FILE_NAME, NULL);
00602
00603 g_free(title);
00604 title = g_strdup((filename != NULL) ? filename : "");
00605 string_cut_extension(title);
00606 }
00607
00608 return title;
00609 }