2 * Copyright (C) 2007-2012 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 static const char *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 static int mm_num_played_score_function(__a_unused
const char *path
,
191 const struct afs_info
*afsi
,
192 __a_unused
const struct afh_info
*afhi
,
195 return mm_compare_num_score_function(afsi
->num_played
, private);
198 struct mm_year_data
{
199 /** Comparator and year given at the mood line. */
200 struct mm_compare_num_data
*cnd
;
201 /** Used to detect Y2K issues. */
202 int32_t current_year
;
205 static int mm_year_parser(int argc
, char **argv
, void **private)
207 int ret
= -E_MOOD_SYNTAX
;
208 struct mm_year_data
*mmyd
= para_malloc(sizeof(*mmyd
));
212 ret
= mm_compare_num_parser(argc
, argv
, (void **)&mmyd
->cnd
);
215 current_time
= time(NULL
);
216 gmt
= gmtime(¤t_time
);
217 /* tm_year is the number of years since 1900 */
218 mmyd
->current_year
= gmt
->tm_year
+ 1900;
226 static int mm_year_score_function(__a_unused
const char *path
,
227 __a_unused
const struct afs_info
*afsi
,
228 const struct afh_info
*afhi
,
231 const struct mm_year_data
*mmyd
= private;
233 int ret
= para_atoi32(afhi
->tags
.year
, &tag_year
);
235 if (ret
< 0) /* year tag not present or not a number */
239 /* try to work around Y2K issues */
240 if (tag_year
< 100) {
242 if (tag_year
+ 100 <= mmyd
->current_year
)
243 tag_year
+= 100; /* assume tag_year >= 2000 */
245 return mm_compare_num_score_function(tag_year
, mmyd
->cnd
);
248 static void mm_year_cleanup(void *private)
250 struct mm_year_data
*mmyd
= private;
256 static int mm_no_attributes_set_parser(int argc
, __a_unused
char **argv
,
257 __a_unused
void **ignored
)
259 return argc
? -E_MOOD_SYNTAX
: 1;
262 static int mm_no_attributes_set_score_function(__a_unused
const char *path
,
263 const struct afs_info
*afsi
,
264 __a_unused
const struct afh_info
*afhi
,
265 __a_unused
const void *data
)
267 if (!afsi
->attributes
)
272 static int mm_path_matches_score_function(const char *path
,
273 __a_unused
const struct afs_info
*afsi
,
274 __a_unused
const struct afh_info
*afhi
,
277 if (fnmatch(data
, path
, 0))
282 static int mm_path_matches_parser(int argc
, char **argv
, void **data
)
285 return -E_MOOD_SYNTAX
;
286 *data
= para_strdup(argv
[1]);
290 static void mm_path_matches_cleanup(void *data
)
295 static int mm_is_set_parser(int argc
, char **argv
, void **bitnum
)
298 unsigned char c
, *res
;
301 return -E_MOOD_SYNTAX
;
302 ret
= get_attribute_bitnum_by_name(argv
[1], &c
);
305 res
= para_malloc(1);
311 static int mm_is_set_score_function(__a_unused
const char *path
,
312 __a_unused
const struct afs_info
*afsi
,
313 __a_unused
const struct afh_info
*afhi
,
316 const unsigned char *bn
= data
;
317 if (afsi
->attributes
& (1ULL << *bn
))
322 #define DEFINE_MOOD_METHOD(_name) \
323 .parser = mm_ ## _name ## _parser, \
324 .score_function = mm_ ## _name ## _score_function, \
327 #define DEFINE_MOOD_METHOD_WITH_CLEANUP(_name) \
328 DEFINE_MOOD_METHOD(_name), \
329 .cleanup = mm_ ## _name ## _cleanup
331 #define DEFINE_REGEX_MOOD_METHOD(_name) \
333 .parser = mm_regex_parser, \
334 .score_function = mm_ ## _name ## _score_function, \
335 .cleanup = mm_regex_cleanup
337 #define DEFINE_COMPARE_NUM_MOOD_METHOD(_name) \
339 .parser = mm_compare_num_parser, \
340 .score_function = mm_ ## _name ## _score_function
342 const struct mood_method mood_methods
[] = {
343 {DEFINE_MOOD_METHOD(no_attributes_set
)},
344 {DEFINE_MOOD_METHOD(is_set
)},
345 {DEFINE_MOOD_METHOD_WITH_CLEANUP(path_matches
)},
346 {DEFINE_MOOD_METHOD_WITH_CLEANUP(year
)},
347 {DEFINE_REGEX_MOOD_METHOD(artist_matches
)},
348 {DEFINE_REGEX_MOOD_METHOD(title_matches
)},
349 {DEFINE_REGEX_MOOD_METHOD(album_matches
)},
350 {DEFINE_REGEX_MOOD_METHOD(comment_matches
)},
351 {DEFINE_COMPARE_NUM_MOOD_METHOD(bitrate
)},
352 {DEFINE_COMPARE_NUM_MOOD_METHOD(frequency
)},
353 {DEFINE_COMPARE_NUM_MOOD_METHOD(channels
)},
354 {DEFINE_COMPARE_NUM_MOOD_METHOD(num_played
)},