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 /** The comparators for numeric mood methods (year, bitrate, ...). */
21 #define MOOD_COMPARATORS \
23 MC(LESS_OR_EQUAL, <=) \
29 MC(GREATER_OR_EQUAL, >=) \
31 /** Prefix mood comparator name with "_MC", example: MC_LESS. */
32 #define MC(a, b) MC_ ## a,
33 /** Each mood comparator is identified by an integer of this type. */
34 enum mood_comparator_id
{MOOD_COMPARATORS NUM_MOOD_COMPARATORS
};
36 /** Stringfied mood comparator, example: "<". */
38 /** Array of mood comparators represented as C strings ("<", "<=", ...). */
39 static const char *mood_comparators
[] = {MOOD_COMPARATORS
};
42 static int parse_mood_comparator(const char *word
)
46 for (i
= 0; i
< NUM_MOOD_COMPARATORS
; i
++)
47 if (!strcmp(word
, mood_comparators
[i
]))
49 return -E_MOOD_SYNTAX
;
52 struct mm_compare_num_data
{
53 /** <, <=, =, !=, >=, or >. */
54 enum mood_comparator_id id
;
55 /** The value given at the mood line. */
59 static int mm_compare_num_score_function(int32_t val
,
60 const struct mm_compare_num_data
*cnd
)
63 int32_t arg
= cnd
->arg
;
67 res
= val
< arg
; break;
68 case MC_LESS_OR_EQUAL
:
69 res
= val
<= arg
; break;
72 res
= val
== arg
; break;
75 res
= val
!= arg
; break;
77 res
= val
> arg
; break;
78 case MC_GREATER_OR_EQUAL
:
79 res
= val
>= arg
; break;
81 PARA_EMERG_LOG("BUG: invalid mood comparator\n");
84 return res
? 100 : -100;
87 static int mm_compare_num_parser(int argc
, char **argv
, void **private)
90 enum mood_comparator_id id
;
92 struct mm_compare_num_data
*cnd
;
94 return -E_MOOD_SYNTAX
;
95 ret
= parse_mood_comparator(argv
[1]);
99 ret
= para_atoi32(argv
[2], &arg
);
102 cnd
= para_malloc(sizeof(struct mm_compare_num_data
));
109 static int mm_regex_parser(int argc
, char **argv
, void **private)
115 return -E_MOOD_SYNTAX
;
116 preg
= para_malloc(sizeof(*preg
));
117 ret
= para_regcomp(preg
, argv
[1], REG_EXTENDED
| REG_NOSUB
);
126 static int mm_regex_score_function(const regex_t
*preg
, const char *pattern
)
128 return regexec(preg
, pattern
, 0, NULL
, 0) == 0? 100 : -100;
131 static void mm_regex_cleanup(void *private)
133 regex_t
*preg
= private;
138 static int mm_artist_matches_score_function(__a_unused
const char *path
,
139 __a_unused
const struct afs_info
*afsi
,
140 const struct afh_info
*afhi
,
143 return mm_regex_score_function(private, afhi
->tags
.artist
);
146 static int mm_title_matches_score_function(__a_unused
const char *path
,
147 __a_unused
const struct afs_info
*afsi
,
148 const struct afh_info
*afhi
,
151 return mm_regex_score_function(private, afhi
->tags
.title
);
154 static int mm_album_matches_score_function(__a_unused
const char *path
,
155 __a_unused
const struct afs_info
*afsi
,
156 const struct afh_info
*afhi
,
159 return mm_regex_score_function(private, afhi
->tags
.album
);
162 static int mm_comment_matches_score_function(__a_unused
const char *path
,
163 __a_unused
const struct afs_info
*afsi
,
164 const struct afh_info
*afhi
,
167 return mm_regex_score_function(private, afhi
->tags
.comment
);
170 static int mm_bitrate_score_function(__a_unused
const char *path
,
171 __a_unused
const struct afs_info
*afsi
,
172 const struct afh_info
*afhi
,
175 return mm_compare_num_score_function(afhi
->bitrate
, private);
178 static int mm_frequency_score_function(__a_unused
const char *path
,
179 __a_unused
const struct afs_info
*afsi
,
180 const struct afh_info
*afhi
,
183 return mm_compare_num_score_function(afhi
->frequency
, private);
186 static int mm_channels_score_function(__a_unused
const char *path
,
187 __a_unused
const struct afs_info
*afsi
,
188 const struct afh_info
*afhi
,
191 return mm_compare_num_score_function(afhi
->channels
, private);
194 static int mm_num_played_score_function(__a_unused
const char *path
,
195 const struct afs_info
*afsi
,
196 __a_unused
const struct afh_info
*afhi
,
199 return mm_compare_num_score_function(afsi
->num_played
, private);
202 struct mm_year_data
{
203 /** Comparator and year given at the mood line. */
204 struct mm_compare_num_data
*cnd
;
205 /** Used to detect Y2K issues. */
206 int32_t current_year
;
209 static int mm_year_parser(int argc
, char **argv
, void **private)
212 struct mm_year_data
*mmyd
= para_malloc(sizeof(*mmyd
));
216 ret
= mm_compare_num_parser(argc
, argv
, (void **)&mmyd
->cnd
);
219 current_time
= time(NULL
);
220 gmt
= gmtime(¤t_time
);
221 /* tm_year is the number of years since 1900 */
222 mmyd
->current_year
= gmt
->tm_year
+ 1900;
230 static int mm_year_score_function(__a_unused
const char *path
,
231 __a_unused
const struct afs_info
*afsi
,
232 const struct afh_info
*afhi
,
235 const struct mm_year_data
*mmyd
= private;
237 int ret
= para_atoi32(afhi
->tags
.year
, &tag_year
);
239 if (ret
< 0) /* year tag not present or not a number */
243 /* try to work around Y2K issues */
244 if (tag_year
< 100) {
246 if (tag_year
+ 100 <= mmyd
->current_year
)
247 tag_year
+= 100; /* assume tag_year >= 2000 */
249 return mm_compare_num_score_function(tag_year
, mmyd
->cnd
);
252 static void mm_year_cleanup(void *private)
254 struct mm_year_data
*mmyd
= private;
260 static int mm_no_attributes_set_parser(int argc
, __a_unused
char **argv
,
261 __a_unused
void **ignored
)
263 return argc
? -E_MOOD_SYNTAX
: 1;
266 static int mm_no_attributes_set_score_function(__a_unused
const char *path
,
267 const struct afs_info
*afsi
,
268 __a_unused
const struct afh_info
*afhi
,
269 __a_unused
const void *data
)
271 if (!afsi
->attributes
)
276 static int mm_path_matches_score_function(const char *path
,
277 __a_unused
const struct afs_info
*afsi
,
278 __a_unused
const struct afh_info
*afhi
,
281 if (fnmatch(data
, path
, 0))
286 static int mm_path_matches_parser(int argc
, char **argv
, void **data
)
289 return -E_MOOD_SYNTAX
;
290 *data
= para_strdup(argv
[1]);
294 static void mm_path_matches_cleanup(void *data
)
299 static int mm_is_set_parser(int argc
, char **argv
, void **bitnum
)
302 unsigned char c
, *res
;
305 return -E_MOOD_SYNTAX
;
306 ret
= get_attribute_bitnum_by_name(argv
[1], &c
);
309 res
= para_malloc(1);
315 static int mm_is_set_score_function(__a_unused
const char *path
,
316 __a_unused
const struct afs_info
*afsi
,
317 __a_unused
const struct afh_info
*afhi
,
320 const unsigned char *bn
= data
;
321 if (afsi
->attributes
& (1ULL << *bn
))
326 #define DEFINE_MOOD_METHOD(_name) \
327 .parser = mm_ ## _name ## _parser, \
328 .score_function = mm_ ## _name ## _score_function, \
331 #define DEFINE_MOOD_METHOD_WITH_CLEANUP(_name) \
332 DEFINE_MOOD_METHOD(_name), \
333 .cleanup = mm_ ## _name ## _cleanup
335 #define DEFINE_REGEX_MOOD_METHOD(_name) \
337 .parser = mm_regex_parser, \
338 .score_function = mm_ ## _name ## _score_function, \
339 .cleanup = mm_regex_cleanup
341 #define DEFINE_COMPARE_NUM_MOOD_METHOD(_name) \
343 .parser = mm_compare_num_parser, \
344 .score_function = mm_ ## _name ## _score_function
346 const struct mood_method mood_methods
[] = {
347 {DEFINE_MOOD_METHOD(no_attributes_set
)},
348 {DEFINE_MOOD_METHOD(is_set
)},
349 {DEFINE_MOOD_METHOD_WITH_CLEANUP(path_matches
)},
350 {DEFINE_MOOD_METHOD_WITH_CLEANUP(year
)},
351 {DEFINE_REGEX_MOOD_METHOD(artist_matches
)},
352 {DEFINE_REGEX_MOOD_METHOD(title_matches
)},
353 {DEFINE_REGEX_MOOD_METHOD(album_matches
)},
354 {DEFINE_REGEX_MOOD_METHOD(comment_matches
)},
355 {DEFINE_COMPARE_NUM_MOOD_METHOD(bitrate
)},
356 {DEFINE_COMPARE_NUM_MOOD_METHOD(frequency
)},
357 {DEFINE_COMPARE_NUM_MOOD_METHOD(channels
)},
358 {DEFINE_COMPARE_NUM_MOOD_METHOD(num_played
)},