1 /* Copyright (C) 2007 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
3 /** \file mm.c Paraslash's mood methods. */
17 /** The comparators for numeric mood methods (year, bitrate, ...). */
18 #define MOOD_COMPARATORS \
20 MC(LESS_OR_EQUAL, <=) \
26 MC(GREATER_OR_EQUAL, >=) \
28 /** Prefix mood comparator name with "_MC", example: MC_LESS. */
29 #define MC(a, b) MC_ ## a,
30 /** Each mood comparator is identified by an integer of this type. */
31 enum mood_comparator_id
{MOOD_COMPARATORS NUM_MOOD_COMPARATORS
};
33 /** Stringfied mood comparator, example: "<". */
35 /** Array of mood comparators represented as C strings ("<", "<=", ...). */
36 static const char *mood_comparators
[] = {MOOD_COMPARATORS
};
39 static int parse_mood_comparator(const char *word
)
43 for (i
= 0; i
< NUM_MOOD_COMPARATORS
; i
++)
44 if (!strcmp(word
, mood_comparators
[i
]))
46 return -E_MOOD_SYNTAX
;
49 struct mm_compare_num_data
{
50 /** <, <=, =, !=, >=, or >. */
51 enum mood_comparator_id id
;
52 /** The value given at the mood line. */
56 static int mm_compare_num_score_function(int32_t val
,
57 const struct mm_compare_num_data
*cnd
)
60 int32_t arg
= cnd
->arg
;
64 res
= val
< arg
; break;
65 case MC_LESS_OR_EQUAL
:
66 res
= val
<= arg
; break;
69 res
= val
== arg
; break;
72 res
= val
!= arg
; break;
74 res
= val
> arg
; break;
75 case MC_GREATER_OR_EQUAL
:
76 res
= val
>= arg
; break;
78 PARA_EMERG_LOG("BUG: invalid mood comparator\n");
81 return res
? 100 : -100;
84 static int mm_compare_num_parser(int argc
, char **argv
, void **private)
87 enum mood_comparator_id id
;
89 struct mm_compare_num_data
*cnd
;
91 return -E_MOOD_SYNTAX
;
92 ret
= parse_mood_comparator(argv
[1]);
96 ret
= para_atoi32(argv
[2], &arg
);
99 cnd
= para_malloc(sizeof(struct mm_compare_num_data
));
106 static int mm_regex_parser(int argc
, char **argv
, void **private)
112 return -E_MOOD_SYNTAX
;
113 preg
= para_malloc(sizeof(*preg
));
114 ret
= para_regcomp(preg
, argv
[1], REG_EXTENDED
| REG_NOSUB
);
123 static int mm_regex_score_function(const regex_t
*preg
, const char *pattern
)
125 return regexec(preg
, pattern
, 0, NULL
, 0) == 0? 100 : -100;
128 static void mm_regex_cleanup(void *private)
130 regex_t
*preg
= private;
135 static int mm_artist_matches_score_function(__a_unused
const char *path
,
136 __a_unused
const struct afs_info
*afsi
,
137 const struct afh_info
*afhi
,
140 return mm_regex_score_function(private, afhi
->tags
.artist
);
143 static int mm_title_matches_score_function(__a_unused
const char *path
,
144 __a_unused
const struct afs_info
*afsi
,
145 const struct afh_info
*afhi
,
148 return mm_regex_score_function(private, afhi
->tags
.title
);
151 static int mm_album_matches_score_function(__a_unused
const char *path
,
152 __a_unused
const struct afs_info
*afsi
,
153 const struct afh_info
*afhi
,
156 return mm_regex_score_function(private, afhi
->tags
.album
);
159 static int mm_comment_matches_score_function(__a_unused
const char *path
,
160 __a_unused
const struct afs_info
*afsi
,
161 const struct afh_info
*afhi
,
164 return mm_regex_score_function(private, afhi
->tags
.comment
);
167 static int mm_bitrate_score_function(__a_unused
const char *path
,
168 __a_unused
const struct afs_info
*afsi
,
169 const struct afh_info
*afhi
,
172 return mm_compare_num_score_function(afhi
->bitrate
, private);
175 static int mm_frequency_score_function(__a_unused
const char *path
,
176 __a_unused
const struct afs_info
*afsi
,
177 const struct afh_info
*afhi
,
180 return mm_compare_num_score_function(afhi
->frequency
, private);
183 static int mm_channels_score_function(__a_unused
const char *path
,
184 __a_unused
const struct afs_info
*afsi
,
185 const struct afh_info
*afhi
,
188 return mm_compare_num_score_function(afhi
->channels
, private);
191 static int mm_image_id_score_function(__a_unused
const char *path
,
192 const struct afs_info
*afsi
,
193 __a_unused
const struct afh_info
*afhi
,
196 return mm_compare_num_score_function(afsi
->image_id
, private);
199 static int mm_lyrics_id_score_function(__a_unused
const char *path
,
200 const struct afs_info
*afsi
,
201 __a_unused
const struct afh_info
*afhi
,
204 return mm_compare_num_score_function(afsi
->lyrics_id
, private);
207 static int mm_num_played_score_function(__a_unused
const char *path
,
208 const struct afs_info
*afsi
,
209 __a_unused
const struct afh_info
*afhi
,
212 return mm_compare_num_score_function(afsi
->num_played
, private);
215 struct mm_year_data
{
216 /** Comparator and year given at the mood line. */
217 struct mm_compare_num_data
*cnd
;
218 /** Used to detect Y2K issues. */
219 int32_t current_year
;
222 static int mm_year_parser(int argc
, char **argv
, void **private)
225 struct mm_year_data
*mmyd
= para_malloc(sizeof(*mmyd
));
229 ret
= mm_compare_num_parser(argc
, argv
, (void **)&mmyd
->cnd
);
232 current_time
= time(NULL
);
233 gmt
= gmtime(¤t_time
);
234 /* tm_year is the number of years since 1900 */
235 mmyd
->current_year
= gmt
->tm_year
+ 1900;
243 static int mm_year_score_function(__a_unused
const char *path
,
244 __a_unused
const struct afs_info
*afsi
,
245 const struct afh_info
*afhi
,
248 const struct mm_year_data
*mmyd
= private;
250 int ret
= para_atoi32(afhi
->tags
.year
, &tag_year
);
252 if (ret
< 0) /* year tag not present or not a number */
256 /* try to work around Y2K issues */
257 if (tag_year
< 100) {
259 if (tag_year
+ 100 <= mmyd
->current_year
)
260 tag_year
+= 100; /* assume tag_year >= 2000 */
262 return mm_compare_num_score_function(tag_year
, mmyd
->cnd
);
265 static void mm_year_cleanup(void *private)
267 struct mm_year_data
*mmyd
= private;
273 static int mm_no_attributes_set_parser(int argc
, __a_unused
char **argv
,
274 __a_unused
void **ignored
)
276 return argc
? -E_MOOD_SYNTAX
: 1;
279 static int mm_no_attributes_set_score_function(__a_unused
const char *path
,
280 const struct afs_info
*afsi
,
281 __a_unused
const struct afh_info
*afhi
,
282 __a_unused
const void *data
)
284 if (!afsi
->attributes
)
289 static int mm_path_matches_score_function(const char *path
,
290 __a_unused
const struct afs_info
*afsi
,
291 __a_unused
const struct afh_info
*afhi
,
294 if (fnmatch(data
, path
, 0))
299 static int mm_path_matches_parser(int argc
, char **argv
, void **data
)
302 return -E_MOOD_SYNTAX
;
303 *data
= para_strdup(argv
[1]);
307 static void mm_path_matches_cleanup(void *data
)
312 static int mm_is_set_parser(int argc
, char **argv
, void **bitnum
)
315 unsigned char c
, *res
;
318 return -E_MOOD_SYNTAX
;
319 ret
= get_attribute_bitnum_by_name(argv
[1], &c
);
322 res
= para_malloc(1);
328 static int mm_is_set_score_function(__a_unused
const char *path
,
329 __a_unused
const struct afs_info
*afsi
,
330 __a_unused
const struct afh_info
*afhi
,
333 const unsigned char *bn
= data
;
334 if (afsi
->attributes
& (1ULL << *bn
))
339 #define DEFINE_MOOD_METHOD(_name) \
340 .parser = mm_ ## _name ## _parser, \
341 .score_function = mm_ ## _name ## _score_function, \
344 #define DEFINE_MOOD_METHOD_WITH_CLEANUP(_name) \
345 DEFINE_MOOD_METHOD(_name), \
346 .cleanup = mm_ ## _name ## _cleanup
348 #define DEFINE_REGEX_MOOD_METHOD(_name) \
350 .parser = mm_regex_parser, \
351 .score_function = mm_ ## _name ## _score_function, \
352 .cleanup = mm_regex_cleanup
354 #define DEFINE_COMPARE_NUM_MOOD_METHOD(_name) \
356 .parser = mm_compare_num_parser, \
357 .score_function = mm_ ## _name ## _score_function
359 const struct mood_method mood_methods
[] = {
360 {DEFINE_MOOD_METHOD(no_attributes_set
)},
361 {DEFINE_MOOD_METHOD(is_set
)},
362 {DEFINE_MOOD_METHOD_WITH_CLEANUP(path_matches
)},
363 {DEFINE_MOOD_METHOD_WITH_CLEANUP(year
)},
364 {DEFINE_REGEX_MOOD_METHOD(artist_matches
)},
365 {DEFINE_REGEX_MOOD_METHOD(title_matches
)},
366 {DEFINE_REGEX_MOOD_METHOD(album_matches
)},
367 {DEFINE_REGEX_MOOD_METHOD(comment_matches
)},
368 {DEFINE_COMPARE_NUM_MOOD_METHOD(bitrate
)},
369 {DEFINE_COMPARE_NUM_MOOD_METHOD(frequency
)},
370 {DEFINE_COMPARE_NUM_MOOD_METHOD(channels
)},
371 {DEFINE_COMPARE_NUM_MOOD_METHOD(num_played
)},
372 {DEFINE_COMPARE_NUM_MOOD_METHOD(image_id
)},
373 {DEFINE_COMPARE_NUM_MOOD_METHOD(lyrics_id
)},