2 * Copyright (C) 2007-2009 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 const char const *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 static int compare_int32(int32_t a, int32_t b, enum mood_comparator_id id)
55 case MC_LESS_OR_EQUAL:
65 case MC_GREATER_OR_EQUAL:
68 PARA_EMERG_LOG("BUG: invalid mood comparator\n");
71 return res? 100 : -100;
74 static int mm_regex_parser(int argc, char **argv, void **private)
80 return -E_MOOD_SYNTAX;
81 preg = para_malloc(sizeof(*preg));
82 ret = para_regcomp(preg, argv[1], REG_EXTENDED | REG_NOSUB);
91 static int mm_regex_score_function(const regex_t *preg, const char *pattern)
93 return regexec(preg, pattern, 0, NULL, 0) == 0? 100 : -100;
96 static void mm_regex_cleanup(void *private)
98 regex_t *preg = private;
103 static int mm_artist_matches_score_function(__a_unused const char *path,
104 __a_unused const struct afs_info *afsi,
105 const struct afh_info *afhi,
108 return mm_regex_score_function(private, afhi->tags.artist);
111 static int mm_title_matches_score_function(__a_unused const char *path,
112 __a_unused const struct afs_info *afsi,
113 const struct afh_info *afhi,
116 return mm_regex_score_function(private, afhi->tags.title);
119 static int mm_album_matches_score_function(__a_unused const char *path,
120 __a_unused const struct afs_info *afsi,
121 const struct afh_info *afhi,
124 return mm_regex_score_function(private, afhi->tags.album);
127 static int mm_comment_matches_score_function(__a_unused const char *path,
128 __a_unused const struct afs_info *afsi,
129 const struct afh_info *afhi,
132 return mm_regex_score_function(private, afhi->tags.comment);
135 struct mm_year_data {
136 /** The year given at the mood line. */
138 /** Used to detect Y2K issues. */
139 int32_t current_year;
140 /** <, <=, =, !=, >=, or >. */
141 enum mood_comparator_id id;
144 static int mm_year_parser(int argc, char **argv, void **private)
146 int ret = -E_MOOD_SYNTAX;
147 struct mm_year_data *mmyd = para_malloc(sizeof(*mmyd));
153 ret = parse_mood_comparator(argv[1]);
157 ret = para_atoi32(argv[2], &mmyd->year);
160 current_time = time(NULL);
161 gmt = gmtime(¤t_time);
162 /* tm_year is the number of years since 1900 */
163 mmyd->current_year = gmt->tm_year + 1900;
171 static int mm_year_score_function(__a_unused const char *path,
172 __a_unused const struct afs_info *afsi,
173 const struct afh_info *afhi,
176 const struct mm_year_data *mmyd = private;
178 int ret = para_atoi32(afhi->tags.year, &tag_year);
180 if (ret < 0) /* year tag not present or not a number */
184 /* try to work around Y2K issues */
185 if (tag_year < 100) {
187 if (tag_year + 100 <= mmyd->current_year)
188 tag_year += 100; /* assume tag_year >= 2000 */
190 return compare_int32(tag_year, mmyd->year, mmyd->id);
193 static void mm_year_cleanup(void *private)
198 static int mm_no_attributes_set_parser(int argc, __a_unused char **argv,
199 __a_unused void **ignored)
201 return argc? -E_MOOD_SYNTAX : 1;
204 static int mm_no_attributes_set_score_function(__a_unused const char *path,
205 const struct afs_info *afsi,
206 __a_unused const struct afh_info *afhi,
207 __a_unused const void *data)
209 if (!afsi->attributes)
214 static int mm_path_matches_score_function(const char *path,
215 __a_unused const struct afs_info *afsi,
216 __a_unused const struct afh_info *afhi,
219 if (fnmatch(data, path, 0))
224 static int mm_path_matches_parser(int argc, char **argv, void **data)
227 return -E_MOOD_SYNTAX;
228 *data = para_strdup(argv[1]);
232 static void mm_path_matches_cleanup(void *data)
237 static int mm_is_set_parser(int argc, char **argv, void **bitnum)
240 unsigned char c, *res;
243 return -E_MOOD_SYNTAX;
244 ret = get_attribute_bitnum_by_name(argv[1], &c);
247 res = para_malloc(1);
253 static int mm_is_set_score_function(__a_unused const char *path,
254 __a_unused const struct afs_info *afsi,
255 __a_unused const struct afh_info *afhi,
258 const unsigned char *bn = data;
259 if (afsi->attributes & (1ULL << *bn))
264 #define DEFINE_MOOD_METHOD(_name) \
265 .parser = mm_ ## _name ## _parser, \
266 .score_function = mm_ ## _name ## _score_function, \
269 #define DEFINE_MOOD_METHOD_WITH_CLEANUP(_name) \
270 DEFINE_MOOD_METHOD(_name), \
271 .cleanup = mm_ ## _name ## _cleanup
273 #define DEFINE_REGEX_MOOD_METHOD(_name) \
275 .parser = mm_regex_parser, \
276 .score_function = mm_ ## _name ## _score_function, \
277 .cleanup = mm_regex_cleanup
279 const struct mood_method mood_methods[] = {
280 {DEFINE_MOOD_METHOD(no_attributes_set)},
281 {DEFINE_MOOD_METHOD(is_set)},
282 {DEFINE_MOOD_METHOD_WITH_CLEANUP(path_matches)},
283 {DEFINE_MOOD_METHOD_WITH_CLEANUP(year)},
284 {DEFINE_REGEX_MOOD_METHOD(artist_matches)},
285 {DEFINE_REGEX_MOOD_METHOD(title_matches)},
286 {DEFINE_REGEX_MOOD_METHOD(album_matches)},
287 {DEFINE_REGEX_MOOD_METHOD(comment_matches)},