From 5f540c5a4793a704bbdd4e7aaf117b8a3e642002 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Thu, 9 Jul 2009 20:11:55 +0200 Subject: [PATCH] Add the new "year" mood method. This includes a Y2K heuristic for year tags that contain only two digits. If that two-digit number N is less or equal than the current year minus 2000, assume that it means 2000 + N. Otherwise, assume 1900 + N. Examples: 0 -> 2000, 42 -> 1942, 9->2009. --- mood.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/mood.c b/mood.c index f16d9c4c..239911fd 100644 --- a/mood.c +++ b/mood.c @@ -6,6 +6,7 @@ /** \file mood.c Paraslash's mood handling functions. */ +#include #include #include #include @@ -167,6 +168,122 @@ static uint64_t int_sqrt(uint64_t x) return res; } +#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) +{ + 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) { @@ -329,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} }; -- 2.39.5