1#include <assert.h>2#include <stddef.h>3#include <string.h>4#include <strings.h>56#include "fns.h"7#include "mpc.h"89static char *mpd_tag_names[] = {10 "any",11 "artist",12 "artistsort",13 "album",14 "albumsort",15 "albumartist",16 "albumartistsort",17 "title",18 "track",19 "name",20 "genre",21 "date",22 "composer",23 "performer",24 "grouping",25 "comment",26 "disc",27 "label",28 "musicbrainz_artistid",29 "musicbrainz_albumid",30 "musicbrainz_albumartistid",31 "musicbrainz_trackid",32 "musicbrainz_releasetrackid",33 "musicbrainz_workid",34};3536mpc_parser_t *37mpd_tag_name(void)38{39 mpc_parser_t *str, *lstr;40 static mpd_string_array_t a = MPD_STRING_ARY(mpd_tag_names);4142 str = mpc_many1(mpcf_strfold,43 mpc_or(2, mpc_range('a', 'z'), mpc_range('A', 'Z')));44 lstr = mpc_apply(str, mpdf_lowercase);4546 return mpc_check_with(lstr, free, mpd_check_array, &a, "invalid tag");47}4849static mpc_parser_t *50mpd_expr_string(void)51{52 mpc_parser_t *strch, *par;5354 strch = mpc_or(2, mpc_escape(), mpc_noneof("\'"));55 par = mpc_between(mpc_many(mpcf_strfold, strch), free, "'", "'");5657 return mpc_apply(mpc_or(2, par, mpc_string_lit()), mpdf_unescape);58}5960static mpc_val_t *61mpdf_fold_seperator(int n, mpc_val_t **xs)62{63 if (!n)64 return xstrdup("");6566 return mpcf_fst_free(n, xs);67}6869static mpc_parser_t *70mpd_seperator(void)71{72 return mpc_many(mpdf_fold_seperator, mpd_whitespace());73}7475static mpc_parser_t *76mpd_op(mpc_parser_t *par)77{78 return mpc_and(3, mpcf_snd_free, mpd_seperator(), par, mpd_seperator(),79 free, free);80}8182static mpd_operation_t83mpd_str2op(char *str)84{85 if (!strcmp(str, "=="))86 return MPD_OP_EQUAL;87 else if (!strcmp(str, "!="))88 return MPD_OP_NEQUAL;89 else if (!strcmp(str, "contains"))90 return MPD_OP_CONTAINS;91 else if (!strcmp(str, "=~"))92 return MPD_OP_MATCH;93 else if (!strcmp(str, "!~"))94 return MPD_OP_NMATCH;95 else96 return MPD_OP_NONE;97}9899static mpc_val_t *100mpdf_fold_expression(int n, mpc_val_t **xs)101{102 mpd_expression_t *expr;103104 assert(n == 3);105106 expr = xmalloc(sizeof(*expr));107 expr->name = (char *)xs[0];108 expr->op = mpd_str2op((char *)xs[1]);109 expr->o1.str = (char *)xs[2];110 expr->next = NULL;111112 free(xs[1]);113 return expr;114}115116static mpc_val_t *117mpdf_fold_expressions(int n, mpc_val_t **xs)118{119 mpd_expression_t *expr;120121 expr = xmalloc(sizeof(*expr));122 expr->op = MPD_OP_NONE;123124 if (n == 3) {125 expr->name = (char *)xs[1];126 assert(!strcmp(expr->name, "AND"));127 expr->o1.expr = (mpd_expression_t *)xs[0];128 expr->next = (mpd_expression_t *)xs[2];129 } else if (n == 2) {130 expr->name = xstrdup("NOT");131 assert(!strcmp((char *)xs[0], "!"));132 expr->o1.expr = (mpd_expression_t *)xs[1];133 expr->next = NULL;134 free(xs[0]);135 } else {136 assert(0);137 }138139 return expr;140}141142static mpc_parser_t *143mpd_tag(void)144{145 mpc_parser_t *op;146147 op = mpc_or(5, mpc_string("=="), mpc_string("!="),148 mpc_string("contains"), mpc_string("=~"), mpc_string("!~"));149 return mpc_and(3, mpdf_fold_expression, mpd_tag_name(), mpd_op(op),150 mpd_expr_string(), free, free);151}152153static mpc_parser_t *154mpd_file(void)155{156 return mpc_and(3, mpdf_fold_expression, mpc_string("file"),157 mpd_op(mpc_string("==")), mpd_expr_string(), free, free);158}159160static mpc_parser_t *161mpd_base(void)162{163 return mpc_and(3, mpdf_fold_expression, mpc_string("base"),164 mpd_seperator(), mpd_expr_string(), free, free);165}166167static mpc_parser_t *168mpd_modified_since(void)169{170 return mpc_and(3, mpdf_fold_expression, mpc_string("modified-since"),171 mpd_seperator(), mpd_expr_string(), free, free);172}173174static mpc_parser_t *175mpd_audio_format(void)176{177 mpc_parser_t *ops;178179 ops = mpc_or(2, mpc_string("=="), mpc_string("=~"));180 return mpc_and(3, mpdf_fold_expression, mpc_string("AudioFormat"),181 mpd_op(ops), mpd_expr_string(), free, free);182}183184static mpc_parser_t *185mpd_base_exprs(void)186{187 return mpc_or(5, mpd_file(), mpd_base(), mpd_modified_since(),188 mpd_audio_format(), mpd_tag());189}190191void192mpd_free_expression(void *ptr)193{194 mpd_expression_t *expr;195196 expr = (mpd_expression_t *)ptr;197 if (!strcmp(expr->name, "AND") || !strcmp(expr->name, "NOT"))198 mpd_free_expression(expr->o1.expr);199 else200 free(expr->o1.str);201202 if (expr->next)203 mpd_free_expression(expr->next);204205 free(expr->name);206 free(expr);207}208209mpd_expression_t *210mpd_expression(char *str)211{212 mpc_result_t r;213 mpc_parser_t *expr;214 mpd_expression_t *ret;215216 expr = mpc_new("expr");217 mpc_define(expr,218 mpc_between(mpc_or(3, mpd_base_exprs(),219 mpc_and(3, mpdf_fold_expressions, expr,220 mpd_op(mpc_string("AND")), expr,221 mpd_free_expression, free),222 mpc_and(2, mpdf_fold_expressions,223 mpc_char('!'), expr, free)),224 mpd_free_expression, "(", ")"));225226 if (mpc_parse("", str, expr, &r)) {227 ret = (mpd_expression_t *)r.output;228 } else {229 mpc_err_delete(r.error);230 ret = NULL;231 }232233 mpc_cleanup(1, expr);234 return ret;235}