]> git.tuebingen.mpg.de Git - paraslash.git/blobdiff - mm.c
Move mood methods to a separate file.
[paraslash.git] / mm.c
diff --git a/mm.c b/mm.c
new file mode 100644 (file)
index 0000000..0130cbc
--- /dev/null
+++ b/mm.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2007-2009 Andre Noll <maan@systemlinux.org>
+ *
+ * Licensed under the GPL v2. For licencing details see COPYING.
+ */
+
+/** \file mm.c Paraslash's mood methods. */
+
+#include <time.h>
+#include <regex.h>
+#include <fnmatch.h>
+#include <osl.h>
+
+#include "para.h"
+#include "error.h"
+#include "string.h"
+#include "afh.h"
+#include "afs.h"
+#include "mm.h"
+
+#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(&current_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,
+               const struct afs_info *afsi,
+               __a_unused const struct afh_info *afhi,
+               __a_unused const void *data)
+{
+       if (!afsi->attributes)
+               return 100;
+       return -100;
+}
+
+static int mm_path_matches_score_function(const char *path,
+               __a_unused const struct afs_info *afsi,
+               __a_unused const struct afh_info *afhi,
+               const void *data)
+{
+       if (fnmatch(data, path, 0))
+               return -100;
+       return 100;
+}
+
+static int mm_path_matches_parser(int argc, char **argv, void **data)
+{
+       if (argc != 1)
+               return -E_MOOD_SYNTAX;
+       *data = para_strdup(argv[1]);
+       return 1;
+}
+
+static void mm_path_matches_cleanup(void *data)
+{
+       free(data);
+}
+
+static int mm_is_set_parser(int argc, char **argv, void **bitnum)
+{
+       int ret;
+       unsigned char c, *res;
+
+       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,
+               __a_unused const struct afs_info *afsi,
+               __a_unused const struct afh_info *afhi,
+               const void *data)
+{
+       const unsigned char *bn = data;
+       if (afsi->attributes & (1ULL << *bn))
+               return 100;
+       return -100;
+}
+
+#define DEFINE_MOOD_METHOD(_name) \
+.parser = mm_ ## _name ## _parser, \
+.score_function = mm_ ## _name ## _score_function, \
+.name = #_name
+
+#define DEFINE_MOOD_METHOD_WITH_CLEANUP(_name) \
+       DEFINE_MOOD_METHOD(_name), \
+       .cleanup = mm_ ## _name ## _cleanup
+
+const struct mood_method mood_methods[] = {
+       {DEFINE_MOOD_METHOD(no_attributes_set)},
+       {DEFINE_MOOD_METHOD(is_set)},
+       {DEFINE_MOOD_METHOD_WITH_CLEANUP(path_matches)},
+       {DEFINE_MOOD_METHOD_WITH_CLEANUP(year)},
+       {.parser = NULL}
+};
+