catblob: Fix "no matches" message.
[paraslash.git] / mm.c
diff --git a/mm.c b/mm.c
index 0130cbc..af99a36 100644 (file)
--- a/mm.c
+++ b/mm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007-2009 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 2007-2011 Andre Noll <maan@systemlinux.org>
  *
  * Licensed under the GPL v2. For licencing details see COPYING.
  */
@@ -32,7 +32,7 @@
 enum mood_comparator_id {MOOD_COMPARATORS NUM_MOOD_COMPARATORS};
 #undef MC
 #define MC(a, b) # b,
-const char const *mood_comparators[] = {MOOD_COMPARATORS};
+static const char *mood_comparators[] = {MOOD_COMPARATORS};
 #undef MC
 
 static int parse_mood_comparator(const char *word)
@@ -45,25 +45,34 @@ static int parse_mood_comparator(const char *word)
        return -E_MOOD_SYNTAX;
 }
 
-static int compare_int32(int32_t a, int32_t b, enum mood_comparator_id id)
+struct mm_compare_num_data {
+       /** <, <=, =, !=, >=, or >. */
+       enum mood_comparator_id id;
+       /** The value given at the mood line. */
+       int32_t arg;
+};
+
+static int mm_compare_num_score_function(int32_t val,
+               const struct mm_compare_num_data *cnd)
 {
        int res;
+       int32_t arg = cnd->arg;
 
-       switch (id) {
+       switch (cnd->id) {
        case MC_LESS:
-               res = a < b; break;
+               res = val < arg; break;
        case MC_LESS_OR_EQUAL:
-               res = a <= b; break;
+               res = val <= arg; break;
        case MC_EQUAL:
        case MC_EQUAL2:
-               res = a == b; break;
+               res = val == arg; break;
        case MC_NOT_EQUAL:
        case MC_NOT_EQUAL2:
-               res = a != b; break;
+               res = val != arg; break;
        case MC_GREATER:
-               res = a > b; break;
+               res = val > arg; break;
        case MC_GREATER_OR_EQUAL:
-               res = a >= b; break;
+               res = val >= arg; break;
        default:
                PARA_EMERG_LOG("BUG: invalid mood comparator\n");
                exit(EXIT_FAILURE);
@@ -71,13 +80,126 @@ static int compare_int32(int32_t a, int32_t b, enum mood_comparator_id id)
        return res? 100 : -100;
 }
 
+static int mm_compare_num_parser(int argc, char **argv, void **private)
+{
+       int ret;
+       enum mood_comparator_id id;
+       int32_t arg;
+       struct mm_compare_num_data *cnd;
+       if (argc != 2)
+               return -E_MOOD_SYNTAX;
+       ret = parse_mood_comparator(argv[1]);
+       if (ret < 0)
+               return ret;
+       id = ret;
+       ret = para_atoi32(argv[2], &arg);
+       if (ret < 0)
+               return ret;
+       cnd = para_malloc(sizeof(struct mm_compare_num_data));
+       cnd->id = id;
+       cnd->arg = arg;
+       *private = cnd;
+       return 1;
+}
+
+static int mm_regex_parser(int argc, char **argv, void **private)
+{
+       regex_t *preg;
+       int ret;
+
+       if (argc != 1)
+               return -E_MOOD_SYNTAX;
+       preg = para_malloc(sizeof(*preg));
+       ret = para_regcomp(preg, argv[1], REG_EXTENDED | REG_NOSUB);
+       if (ret < 0) {
+               free(preg);
+               return ret;
+       }
+       *private = preg;
+       return 1;
+}
+
+static int mm_regex_score_function(const regex_t *preg, const char *pattern)
+{
+       return regexec(preg, pattern, 0, NULL, 0) == 0? 100 : -100;
+}
+
+static void mm_regex_cleanup(void *private)
+{
+       regex_t *preg = private;
+       regfree(preg);
+       free(preg);
+}
+
+static int mm_artist_matches_score_function(__a_unused const char *path,
+               __a_unused const struct afs_info *afsi,
+               const struct afh_info *afhi,
+               const void *private)
+{
+       return mm_regex_score_function(private, afhi->tags.artist);
+}
+
+static int mm_title_matches_score_function(__a_unused const char *path,
+               __a_unused const struct afs_info *afsi,
+               const struct afh_info *afhi,
+               const void *private)
+{
+       return mm_regex_score_function(private, afhi->tags.title);
+}
+
+static int mm_album_matches_score_function(__a_unused const char *path,
+               __a_unused const struct afs_info *afsi,
+               const struct afh_info *afhi,
+               const void *private)
+{
+       return mm_regex_score_function(private, afhi->tags.album);
+}
+
+static int mm_comment_matches_score_function(__a_unused const char *path,
+               __a_unused const struct afs_info *afsi,
+               const struct afh_info *afhi,
+               const void *private)
+{
+       return mm_regex_score_function(private, afhi->tags.comment);
+}
+
+static int mm_bitrate_score_function(__a_unused const char *path,
+               __a_unused const struct afs_info *afsi,
+               const struct afh_info *afhi,
+               const void *private)
+{
+       return mm_compare_num_score_function(afhi->bitrate, private);
+}
+
+static int mm_frequency_score_function(__a_unused const char *path,
+               __a_unused const struct afs_info *afsi,
+               const struct afh_info *afhi,
+               const void *private)
+{
+       return mm_compare_num_score_function(afhi->frequency, private);
+}
+
+static int mm_channels_score_function(__a_unused const char *path,
+               __a_unused const struct afs_info *afsi,
+               const struct afh_info *afhi,
+               const void *private)
+{
+       return mm_compare_num_score_function(afhi->channels, private);
+}
+
+static int mm_num_played_score_function(__a_unused const char *path,
+               const struct afs_info *afsi,
+               __a_unused const struct afh_info *afhi,
+               const void *private)
+{
+       return mm_compare_num_score_function(afsi->num_played, private);
+}
+
 struct mm_year_data {
-       /** The year given at the mood line. */
-       int32_t year;
+       /** Comparator and year given at the mood line. */
+       struct mm_compare_num_data *cnd;
        /** Used to detect Y2K issues. */
        int32_t current_year;
-       /** <, <=, =, !=, >=, or >. */
-       enum mood_comparator_id id;
 };
 
 static int mm_year_parser(int argc, char **argv, void **private)
@@ -87,13 +209,7 @@ static int mm_year_parser(int argc, char **argv, void **private)
        time_t current_time;
        struct tm *gmt;
 
-       if (argc != 2)
-               goto err;
-       ret = parse_mood_comparator(argv[1]);
-       mmyd->id = ret;
-       if (ret < 0)
-               goto err;
-       ret = para_atoi32(argv[2], &mmyd->year);
+       ret = mm_compare_num_parser(argc, argv, (void **)&mmyd->cnd);
        if (ret < 0)
                goto err;
        current_time = time(NULL);
@@ -126,12 +242,15 @@ static int mm_year_score_function(__a_unused const char *path,
                if (tag_year + 100 <= mmyd->current_year)
                        tag_year += 100; /* assume tag_year >= 2000 */
        }
-       return compare_int32(tag_year, mmyd->year, mmyd->id);
+       return mm_compare_num_score_function(tag_year, mmyd->cnd);
 }
 
 static void mm_year_cleanup(void *private)
 {
-       free(private);
+       struct mm_year_data *mmyd = private;
+
+       free(mmyd->cnd);
+       free(mmyd);
 }
 
 static int mm_no_attributes_set_parser(int argc, __a_unused char **argv,
@@ -209,11 +328,29 @@ static int mm_is_set_score_function(__a_unused const char *path,
        DEFINE_MOOD_METHOD(_name), \
        .cleanup = mm_ ## _name ## _cleanup
 
+#define DEFINE_REGEX_MOOD_METHOD(_name) \
+       .name = #_name, \
+       .parser = mm_regex_parser, \
+       .score_function = mm_ ## _name ## _score_function, \
+       .cleanup = mm_regex_cleanup
+
+#define DEFINE_COMPARE_NUM_MOOD_METHOD(_name) \
+       .name = #_name, \
+       .parser = mm_compare_num_parser, \
+       .score_function = mm_ ## _name ## _score_function
+
 const struct mood_method mood_methods[] = {
        {DEFINE_MOOD_METHOD(no_attributes_set)},
        {DEFINE_MOOD_METHOD(is_set)},
        {DEFINE_MOOD_METHOD_WITH_CLEANUP(path_matches)},
        {DEFINE_MOOD_METHOD_WITH_CLEANUP(year)},
+       {DEFINE_REGEX_MOOD_METHOD(artist_matches)},
+       {DEFINE_REGEX_MOOD_METHOD(title_matches)},
+       {DEFINE_REGEX_MOOD_METHOD(album_matches)},
+       {DEFINE_REGEX_MOOD_METHOD(comment_matches)},
+       {DEFINE_COMPARE_NUM_MOOD_METHOD(bitrate)},
+       {DEFINE_COMPARE_NUM_MOOD_METHOD(frequency)},
+       {DEFINE_COMPARE_NUM_MOOD_METHOD(channels)},
+       {DEFINE_COMPARE_NUM_MOOD_METHOD(num_played)},
        {.parser = NULL}
 };
-