2 * Copyright (C) 2007 Andre Noll <maan@tuebingen.mpg.de>
4 * Licensed under the GPL v2. For licencing details see COPYING.
7 /** \file mm.c Paraslash's mood methods. */
20 #define MOOD_COMPARATORS \
22 MC(LESS_OR_EQUAL, <=) \
28 MC(GREATER_OR_EQUAL, >=) \
30 #define MC(a, b) MC_ ## a,
31 enum mood_comparator_id {MOOD_COMPARATORS NUM_MOOD_COMPARATORS};
34 static const char *mood_comparators[] = {MOOD_COMPARATORS};
37 static int parse_mood_comparator(const char *word)
41 for (i = 0; i < NUM_MOOD_COMPARATORS; i++)
42 if (!strcmp(word, mood_comparators[i]))
44 return -E_MOOD_SYNTAX;
47 struct mm_compare_num_data {
48 /** <, <=, =, !=, >=, or >. */
49 enum mood_comparator_id id;
50 /** The value given at the mood line. */
54 static int mm_compare_num_score_function(int32_t val,
55 const struct mm_compare_num_data *cnd)
58 int32_t arg = cnd->arg;
62 res = val < arg; break;
63 case MC_LESS_OR_EQUAL:
64 res = val <= arg; break;
67 res = val == arg; break;
70 res = val != arg; break;
72 res = val > arg; break;
73 case MC_GREATER_OR_EQUAL:
74 res = val >= arg; break;
76 PARA_EMERG_LOG("BUG: invalid mood comparator\n");
79 return res? 100 : -100;
82 static int mm_compare_num_parser(int argc, char **argv, void **private)
85 enum mood_comparator_id id;
87 struct mm_compare_num_data *cnd;
89 return -E_MOOD_SYNTAX;
90 ret = parse_mood_comparator(argv[1]);
94 ret = para_atoi32(argv[2], &arg);
97 cnd = para_malloc(sizeof(struct mm_compare_num_data));
104 static int mm_regex_parser(int argc, char **argv, void **private)
110 return -E_MOOD_SYNTAX;
111 preg = para_malloc(sizeof(*preg));
112 ret = para_regcomp(preg, argv[1], REG_EXTENDED | REG_NOSUB);
121 static int mm_regex_score_function(const regex_t *preg, const char *pattern)
123 return regexec(preg, pattern, 0, NULL, 0) == 0? 100 : -100;
126 static void mm_regex_cleanup(void *private)
128 regex_t *preg = private;
133 static int mm_artist_matches_score_function(__a_unused const char *path,
134 __a_unused const struct afs_info *afsi,
135 const struct afh_info *afhi,
138 return mm_regex_score_function(private, afhi->tags.artist);
141 static int mm_title_matches_score_function(__a_unused const char *path,
142 __a_unused const struct afs_info *afsi,
143 const struct afh_info *afhi,
146 return mm_regex_score_function(private, afhi->tags.title);
149 static int mm_album_matches_score_function(__a_unused const char *path,
150 __a_unused const struct afs_info *afsi,
151 const struct afh_info *afhi,
154 return mm_regex_score_function(private, afhi->tags.album);
157 static int mm_comment_matches_score_function(__a_unused const char *path,
158 __a_unused const struct afs_info *afsi,
159 const struct afh_info *afhi,
162 return mm_regex_score_function(private, afhi->tags.comment);
165 static int mm_bitrate_score_function(__a_unused const char *path,
166 __a_unused const struct afs_info *afsi,
167 const struct afh_info *afhi,
170 return mm_compare_num_score_function(afhi->bitrate, private);
173 static int mm_frequency_score_function(__a_unused const char *path,
174 __a_unused const struct afs_info *afsi,
175 const struct afh_info *afhi,
178 return mm_compare_num_score_function(afhi->frequency, private);
181 static int mm_channels_score_function(__a_unused const char *path,
182 __a_unused const struct afs_info *afsi,
183 const struct afh_info *afhi,
186 return mm_compare_num_score_function(afhi->channels, private);
189 static int mm_num_played_score_function(__a_unused const char *path,
190 const struct afs_info *afsi,
191 __a_unused const struct afh_info *afhi,
194 return mm_compare_num_score_function(afsi->num_played, private);
197 struct mm_year_data {
198 /** Comparator and year given at the mood line. */
199 struct mm_compare_num_data *cnd;
200 /** Used to detect Y2K issues. */
201 int32_t current_year;
204 static int mm_year_parser(int argc, char **argv, void **private)
207 struct mm_year_data *mmyd = para_malloc(sizeof(*mmyd));
211 ret = mm_compare_num_parser(argc, argv, (void **)&mmyd->cnd);
214 current_time = time(NULL);
215 gmt = gmtime(¤t_time);
216 /* tm_year is the number of years since 1900 */
217 mmyd->current_year = gmt->tm_year + 1900;
225 static int mm_year_score_function(__a_unused const char *path,
226 __a_unused const struct afs_info *afsi,
227 const struct afh_info *afhi,
230 const struct mm_year_data *mmyd = private;
232 int ret = para_atoi32(afhi->tags.year, &tag_year);
234 if (ret < 0) /* year tag not present or not a number */
238 /* try to work around Y2K issues */
239 if (tag_year < 100) {
241 if (tag_year + 100 <= mmyd->current_year)
242 tag_year += 100; /* assume tag_year >= 2000 */
244 return mm_compare_num_score_function(tag_year, mmyd->cnd);
247 static void mm_year_cleanup(void *private)
249 struct mm_year_data *mmyd = private;
255 static int mm_no_attributes_set_parser(int argc, __a_unused char **argv,
256 __a_unused void **ignored)
258 return argc? -E_MOOD_SYNTAX : 1;
261 static int mm_no_attributes_set_score_function(__a_unused const char *path,
262 const struct afs_info *afsi,
263 __a_unused const struct afh_info *afhi,
264 __a_unused const void *data)
266 if (!afsi->attributes)
271 static int mm_path_matches_score_function(const char *path,
272 __a_unused const struct afs_info *afsi,
273 __a_unused const struct afh_info *afhi,
276 if (fnmatch(data, path, 0))
281 static int mm_path_matches_parser(int argc, char **argv, void **data)
284 return -E_MOOD_SYNTAX;
285 *data = para_strdup(argv[1]);
289 static void mm_path_matches_cleanup(void *data)
294 static int mm_is_set_parser(int argc, char **argv, void **bitnum)
297 unsigned char c, *res;
300 return -E_MOOD_SYNTAX;
301 ret = get_attribute_bitnum_by_name(argv[1], &c);
304 res = para_malloc(1);
310 static int mm_is_set_score_function(__a_unused const char *path,
311 __a_unused const struct afs_info *afsi,
312 __a_unused const struct afh_info *afhi,
315 const unsigned char *bn = data;
316 if (afsi->attributes & (1ULL << *bn))
321 #define DEFINE_MOOD_METHOD(_name) \
322 .parser = mm_ ## _name ## _parser, \
323 .score_function = mm_ ## _name ## _score_function, \
326 #define DEFINE_MOOD_METHOD_WITH_CLEANUP(_name) \
327 DEFINE_MOOD_METHOD(_name), \
328 .cleanup = mm_ ## _name ## _cleanup
330 #define DEFINE_REGEX_MOOD_METHOD(_name) \
332 .parser = mm_regex_parser, \
333 .score_function = mm_ ## _name ## _score_function, \
334 .cleanup = mm_regex_cleanup
336 #define DEFINE_COMPARE_NUM_MOOD_METHOD(_name) \
338 .parser = mm_compare_num_parser, \
339 .score_function = mm_ ## _name ## _score_function
341 const struct mood_method mood_methods[] = {
342 {DEFINE_MOOD_METHOD(no_attributes_set)},
343 {DEFINE_MOOD_METHOD(is_set)},
344 {DEFINE_MOOD_METHOD_WITH_CLEANUP(path_matches)},
345 {DEFINE_MOOD_METHOD_WITH_CLEANUP(year)},
346 {DEFINE_REGEX_MOOD_METHOD(artist_matches)},
347 {DEFINE_REGEX_MOOD_METHOD(title_matches)},
348 {DEFINE_REGEX_MOOD_METHOD(album_matches)},
349 {DEFINE_REGEX_MOOD_METHOD(comment_matches)},
350 {DEFINE_COMPARE_NUM_MOOD_METHOD(bitrate)},
351 {DEFINE_COMPARE_NUM_MOOD_METHOD(frequency)},
352 {DEFINE_COMPARE_NUM_MOOD_METHOD(channels)},
353 {DEFINE_COMPARE_NUM_MOOD_METHOD(num_played)},