2 * Copyright (C) 2007-2014 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)
206 int ret
= -E_MOOD_SYNTAX
;
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
)},