X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=mood.c;h=239911fd50538322b844888687c587df02f9a51b;hp=57f3f00ab5b4e11ee4f9d78bb82f683eed361092;hb=8ea8abb73199b32fdd7afdf8825afa42ed8de244;hpb=6bdac07456cb5872f824028912d1049883a9c21f diff --git a/mood.c b/mood.c index 57f3f00a..239911fd 100644 --- a/mood.c +++ b/mood.c @@ -6,7 +6,11 @@ /** \file mood.c Paraslash's mood handling functions. */ +#include +#include #include +#include + #include "para.h" #include "error.h" #include "string.h" @@ -62,11 +66,11 @@ typedef int mood_score_function(const char *path, const struct afs_info *afsi, * Some mood parsers pre-process the data given in the mood line to compute a * structure which depends of the particular mood_method and which is used * later in the mood_score_function of the mood_method. The mood_parser may - * store a pointer to its structure via the second argument. + * store a pointer to its structure via the void** pointer. * * \sa mood_open(), mood_cleanup_function, mood_score_function. */ -typedef int mood_parser(const char *, void **); +typedef int mood_parser(int, char **, void **); /** * Deallocate resources which were allocated by the mood_parser. @@ -164,11 +168,126 @@ static uint64_t int_sqrt(uint64_t x) return res; } -static int mm_no_attributes_set_parser(const char *arg, __a_unused void **ignored) +#define MOOD_COMPARATORS \ + MC(LESS, <) \ + MC(LESS_OR_EQUAL, <=) \ + MC(EQUAL, =) \ + MC(EQUAL2, ==) \ + MC(NOT_EQUAL, !=) \ + MC(NOT_EQUAL2, <>) \ + MC(GREATER, >) \ + MC(GREATER_OR_EQUAL, >=) \ + +#define MC(a, b) MC_ ## a, +enum mood_comparator_id {MOOD_COMPARATORS NUM_MOOD_COMPARATORS}; +#undef MC +#define MC(a, b) # b, +const char const *mood_comparators[] = {MOOD_COMPARATORS}; +#undef MC + +static int parse_mood_comparator(const char *word) +{ + int i; + + for (i = 0; i < NUM_MOOD_COMPARATORS; i++) + if (!strcmp(word, mood_comparators[i])) + return i; + return -E_MOOD_SYNTAX; +} + +static int compare_int32(int32_t a, int32_t b, enum mood_comparator_id id) { - if (arg && *arg) - PARA_WARNING_LOG("ignored junk at eol: %s\n", arg); + int res; + + switch (id) { + case MC_LESS: + res = a < b; break; + case MC_LESS_OR_EQUAL: + res = a <= b; break; + case MC_EQUAL: + case MC_EQUAL2: + res = a == b; break; + case MC_NOT_EQUAL: + case MC_NOT_EQUAL2: + res = a != b; break; + case MC_GREATER: + res = a > b; break; + case MC_GREATER_OR_EQUAL: + res = a >= b; break; + default: + PARA_EMERG_LOG("BUG: invalid mood comparator\n"); + exit(EXIT_FAILURE); + } + return res? 100 : -100; +} + +struct mm_year_data { + /** The year given at the mood line. */ + int32_t year; + /** Used to detect Y2K issues. */ + int32_t current_year; + /** <, <=, =, !=, >=, or >. */ + enum mood_comparator_id id; +}; + +static int mm_year_parser(int argc, char **argv, void **private) +{ + int ret = -E_MOOD_SYNTAX; + struct mm_year_data *mmyd = para_malloc(sizeof(*mmyd)); + time_t current_time; + struct tm *gmt; + + if (argc != 2) + goto err; + ret = parse_mood_comparator(argv[1]); + mmyd->id = ret; + if (ret < 0) + goto err; + ret = para_atoi32(argv[2], &mmyd->year); + if (ret < 0) + goto err; + current_time = time(NULL); + gmt = gmtime(¤t_time); + /* tm_year is the number of years since 1900 */ + mmyd->current_year = gmt->tm_year + 1900; + *private = mmyd; return 1; +err: + free(mmyd); + return ret; +} + +static int mm_year_score_function(__a_unused const char *path, + __a_unused const struct afs_info *afsi, + const struct afh_info *afhi, + const void *private) +{ + const struct mm_year_data *mmyd = private; + int32_t tag_year; + int ret = para_atoi32(afhi->tags.year, &tag_year); + + if (ret < 0) /* year tag not present or not a number */ + return -100; + if (tag_year < 0) + return -100; + /* try to work around Y2K issues */ + if (tag_year < 100) { + tag_year += 1900; + if (tag_year + 100 <= mmyd->current_year) + tag_year += 100; /* assume tag_year >= 2000 */ + } + return compare_int32(tag_year, mmyd->year, mmyd->id); +} + +static void mm_year_cleanup(void *private) +{ + free(private); +} + +static int mm_no_attributes_set_parser(int argc, __a_unused char **argv, + __a_unused void **ignored) +{ + return argc? -E_MOOD_SYNTAX : 1; } static int mm_no_attributes_set_score_function(__a_unused const char *path, @@ -197,11 +316,10 @@ static int mm_played_rarely_score_function(__a_unused const char *path, return -100; } -static int mm_played_rarely_parser(const char *arg, __a_unused void **ignored) +static int mm_played_rarely_parser(int argc, __a_unused char **argv, + __a_unused void **ignored) { - if (arg && *arg) - PARA_WARNING_LOG("ignored junk at eol: %s\n", arg); - return 1; + return argc? -E_MOOD_SYNTAX : 1; } static int mm_path_matches_score_function(const char *path, @@ -214,9 +332,11 @@ static int mm_path_matches_score_function(const char *path, return 100; } -static int mm_path_matches_parser(const char *arg, void **data) +static int mm_path_matches_parser(int argc, char **argv, void **data) { - *data = para_strdup(arg); + if (argc != 1) + return -E_MOOD_SYNTAX; + *data = para_strdup(argv[1]); return 1; } @@ -225,16 +345,20 @@ static void mm_path_matches_cleanup(void *data) free(data); } -static int mm_is_set_parser(const char *arg, void **bitnum) +static int mm_is_set_parser(int argc, char **argv, void **bitnum) { - unsigned char *c = para_malloc(1); - int ret = get_attribute_bitnum_by_name(arg, c); + int ret; + unsigned char c, *res; - if (ret >= 0) - *bitnum = c; - else - free(c); - return ret; + if (argc != 1) + return -E_MOOD_SYNTAX; + ret = get_attribute_bitnum_by_name(argv[1], &c); + if (ret < 0) + return ret; + res = para_malloc(1); + *res = c; + *bitnum = res; + return 1; } static int mm_is_set_score_function(__a_unused const char *path, @@ -266,7 +390,6 @@ static int add_item_score(const struct osl_row *row, struct mood_item *item, lon ret = get_afhi_of_row(row, &afhi); if (ret< 0) return ret; - free(afhi.info_string); /* don't need the tag info */ ret = get_audio_file_path_of_row(row, &path); if (ret< 0) return ret; @@ -323,6 +446,7 @@ static const struct mood_method mood_methods[] = { {DEFINE_MOOD_METHOD(played_rarely)}, {DEFINE_MOOD_METHOD(is_set)}, {DEFINE_MOOD_METHOD_WITH_CLEANUP(path_matches)}, + {DEFINE_MOOD_METHOD_WITH_CLEANUP(year)}, {.parser = NULL} }; @@ -393,17 +517,17 @@ static int parse_mood_line(char *mood_line, void *data) { struct mood_line_parser_data *mlpd = data; char **argv; - char *delim = " \t"; unsigned num_words; char **w; int i, ret; enum mood_line_type mlt = ML_INVALID; struct mood_item *mi = NULL; - char *buf = para_strdup(mood_line); mlpd->line_num++; - num_words = split_args(buf, &argv, delim); - ret = 1; + ret = create_argv(mood_line, " \t", &argv); + if (ret < 0) + return ret; + num_words = ret; if (!num_words) /* empty line */ goto out; w = argv; @@ -476,8 +600,8 @@ check_for_if: ret = -E_MOOD_SYNTAX; if (!mood_methods[i].parser) goto out; - w++; - ret = mood_methods[i].parser(*w, &mi->parser_data); + ret = mood_methods[i].parser(num_words - 1 - (w - argv), w, + &mi->parser_data); if (ret < 0) goto out; mi->method = &mood_methods[i]; @@ -494,8 +618,7 @@ success: (mlt == ML_DENY? "deny" : "score"), mi->method); ret = 1; out: - free(argv); - free(buf); + free_argv(argv); if (ret >= 0) return ret; if (mi) { @@ -537,10 +660,10 @@ static int check_mood(struct osl_row *mood_row, void *data) struct osl_object mood_def; struct mood_line_parser_data mlpd = {.line_num = 0}; - int ret2, ret = mood_get_name_and_def_by_row(mood_row, &mood_name, &mood_def); + int ret = mood_get_name_and_def_by_row(mood_row, &mood_name, &mood_def); if (ret < 0) { - ret2 = para_printf(pb, "failed to get mood definition: %s\n", + para_printf(pb, "failed to get mood definition: %s\n", para_strerror(-ret)); return ret; } @@ -552,7 +675,7 @@ static int check_mood(struct osl_row *mood_row, void *data) ret = for_each_line_ro(mood_def.data, mood_def.size, parse_mood_line, &mlpd); if (ret < 0) - ret2 = para_printf(pb, "%s line %u: %s\n", mood_name, mlpd.line_num, + para_printf(pb, "%s line %u: %s\n", mood_name, mlpd.line_num, para_strerror(-ret)); out: osl_close_disk_object(&mood_def); @@ -972,7 +1095,7 @@ int change_current_mood(char *mood_name) .data = mood_name, .size = strlen(mood_name) + 1 }; - ret = osl_get_row(moods_table, BLOBCOL_NAME, &obj, &row); + ret = osl(osl_get_row(moods_table, BLOBCOL_NAME, &obj, &row)); if (ret < 0) { PARA_NOTICE_LOG("no such mood: %s\n", mood_name); return ret;