2 * Copyright (C) 2007-2009 Andre Noll <maan@systemlinux.org>
4 * Licensed under the GPL v2. For licencing details see COPYING.
7 /** \file mm.c Paraslash's mood methods. */
21 #define MOOD_COMPARATORS \
23 MC(LESS_OR_EQUAL, <=) \
29 MC(GREATER_OR_EQUAL, >=) \
31 #define MC(a, b) MC_ ## a,
32 enum mood_comparator_id {MOOD_COMPARATORS NUM_MOOD_COMPARATORS};
35 const char const *mood_comparators[] = {MOOD_COMPARATORS};
38 static int parse_mood_comparator(const char *word)
42 for (i = 0; i < NUM_MOOD_COMPARATORS; i++)
43 if (!strcmp(word, mood_comparators[i]))
45 return -E_MOOD_SYNTAX;
48 struct mm_compare_num_data {
49 /** <, <=, =, !=, >=, or >. */
50 enum mood_comparator_id id;
51 /** The value given at the mood line. */
55 static int mm_compare_num_score_function(int32_t val,
56 const struct mm_compare_num_data *cnd)
59 int32_t arg = cnd->arg;
63 res = val < arg; break;
64 case MC_LESS_OR_EQUAL:
65 res = val <= arg; break;
68 res = val == arg; break;
71 res = val != arg; break;
73 res = val > arg; break;
74 case MC_GREATER_OR_EQUAL:
75 res = val >= arg; break;
77 PARA_EMERG_LOG("BUG: invalid mood comparator\n");
80 return res? 100 : -100;
83 static int mm_compare_num_parser(int argc, char **argv, void **private)
86 enum mood_comparator_id id;
88 struct mm_compare_num_data *cnd;
90 return -E_MOOD_SYNTAX;
91 ret = parse_mood_comparator(argv[1]);
95 ret = para_atoi32(argv[2], &arg);
98 cnd = para_malloc(sizeof(struct mm_compare_num_data));
105 static int mm_regex_parser(int argc, char **argv, void **private)
111 return -E_MOOD_SYNTAX;
112 preg = para_malloc(sizeof(*preg));
113 ret = para_regcomp(preg, argv[1], REG_EXTENDED | REG_NOSUB);
122 static int mm_regex_score_function(const regex_t *preg, const char *pattern)
124 return regexec(preg, pattern, 0, NULL, 0) == 0? 100 : -100;
127 static void mm_regex_cleanup(void *private)
129 regex_t *preg = private;
134 static int mm_artist_matches_score_function(__a_unused const char *path,
135 __a_unused const struct afs_info *afsi,
136 const struct afh_info *afhi,
139 return mm_regex_score_function(private, afhi->tags.artist);
142 static int mm_title_matches_score_function(__a_unused const char *path,
143 __a_unused const struct afs_info *afsi,
144 const struct afh_info *afhi,
147 return mm_regex_score_function(private, afhi->tags.title);
150 static int mm_album_matches_score_function(__a_unused const char *path,
151 __a_unused const struct afs_info *afsi,
152 const struct afh_info *afhi,
155 return mm_regex_score_function(private, afhi->tags.album);
158 static int mm_comment_matches_score_function(__a_unused const char *path,
159 __a_unused const struct afs_info *afsi,
160 const struct afh_info *afhi,
163 return mm_regex_score_function(private, afhi->tags.comment);
166 static int mm_bitrate_score_function(__a_unused const char *path,
167 __a_unused const struct afs_info *afsi,
168 const struct afh_info *afhi,
171 return mm_compare_num_score_function(afhi->bitrate, private);
174 static int mm_frequency_score_function(__a_unused const char *path,
175 __a_unused const struct afs_info *afsi,
176 const struct afh_info *afhi,
179 return mm_compare_num_score_function(afhi->frequency, private);
182 static int mm_channels_score_function(__a_unused const char *path,
183 __a_unused const struct afs_info *afsi,
184 const struct afh_info *afhi,
187 return mm_compare_num_score_function(afhi->channels, private);
190 struct mm_year_data {
191 /** Comparator and year given at the mood line. */
192 struct mm_compare_num_data *cnd;
193 /** Used to detect Y2K issues. */
194 int32_t current_year;
197 static int mm_year_parser(int argc, char **argv, void **private)
199 int ret = -E_MOOD_SYNTAX;
200 struct mm_year_data *mmyd = para_malloc(sizeof(*mmyd));
204 ret = mm_compare_num_parser(argc, argv, (void **)&mmyd->cnd);
207 current_time = time(NULL);
208 gmt = gmtime(¤t_time);
209 /* tm_year is the number of years since 1900 */
210 mmyd->current_year = gmt->tm_year + 1900;
218 static int mm_year_score_function(__a_unused const char *path,
219 __a_unused const struct afs_info *afsi,
220 const struct afh_info *afhi,
223 const struct mm_year_data *mmyd = private;
225 int ret = para_atoi32(afhi->tags.year, &tag_year);
227 if (ret < 0) /* year tag not present or not a number */
231 /* try to work around Y2K issues */
232 if (tag_year < 100) {
234 if (tag_year + 100 <= mmyd->current_year)
235 tag_year += 100; /* assume tag_year >= 2000 */
237 return mm_compare_num_score_function(tag_year, mmyd->cnd);
240 static void mm_year_cleanup(void *private)
242 struct mm_year_data *mmyd = private;
248 static int mm_no_attributes_set_parser(int argc, __a_unused char **argv,
249 __a_unused void **ignored)
251 return argc? -E_MOOD_SYNTAX : 1;
254 static int mm_no_attributes_set_score_function(__a_unused const char *path,
255 const struct afs_info *afsi,
256 __a_unused const struct afh_info *afhi,
257 __a_unused const void *data)
259 if (!afsi->attributes)
264 static int mm_path_matches_score_function(const char *path,
265 __a_unused const struct afs_info *afsi,
266 __a_unused const struct afh_info *afhi,
269 if (fnmatch(data, path, 0))
274 static int mm_path_matches_parser(int argc, char **argv, void **data)
277 return -E_MOOD_SYNTAX;
278 *data = para_strdup(argv[1]);
282 static void mm_path_matches_cleanup(void *data)
287 static int mm_is_set_parser(int argc, char **argv, void **bitnum)
290 unsigned char c, *res;
293 return -E_MOOD_SYNTAX;
294 ret = get_attribute_bitnum_by_name(argv[1], &c);
297 res = para_malloc(1);
303 static int mm_is_set_score_function(__a_unused const char *path,
304 __a_unused const struct afs_info *afsi,
305 __a_unused const struct afh_info *afhi,
308 const unsigned char *bn = data;
309 if (afsi->attributes & (1ULL << *bn))
314 #define DEFINE_MOOD_METHOD(_name) \
315 .parser = mm_ ## _name ## _parser, \
316 .score_function = mm_ ## _name ## _score_function, \
319 #define DEFINE_MOOD_METHOD_WITH_CLEANUP(_name) \
320 DEFINE_MOOD_METHOD(_name), \
321 .cleanup = mm_ ## _name ## _cleanup
323 #define DEFINE_REGEX_MOOD_METHOD(_name) \
325 .parser = mm_regex_parser, \
326 .score_function = mm_ ## _name ## _score_function, \
327 .cleanup = mm_regex_cleanup
329 #define DEFINE_COMPARE_NUM_MOOD_METHOD(_name) \
331 .parser = mm_compare_num_parser, \
332 .score_function = mm_ ## _name ## _score_function
334 const struct mood_method mood_methods[] = {
335 {DEFINE_MOOD_METHOD(no_attributes_set)},
336 {DEFINE_MOOD_METHOD(is_set)},
337 {DEFINE_MOOD_METHOD_WITH_CLEANUP(path_matches)},
338 {DEFINE_MOOD_METHOD_WITH_CLEANUP(year)},
339 {DEFINE_REGEX_MOOD_METHOD(artist_matches)},
340 {DEFINE_REGEX_MOOD_METHOD(title_matches)},
341 {DEFINE_REGEX_MOOD_METHOD(album_matches)},
342 {DEFINE_REGEX_MOOD_METHOD(comment_matches)},
343 {DEFINE_COMPARE_NUM_MOOD_METHOD(bitrate)},
344 {DEFINE_COMPARE_NUM_MOOD_METHOD(frequency)},
345 {DEFINE_COMPARE_NUM_MOOD_METHOD(channels)},