aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/calendar.h11
-rw-r--r--src/entry.c178
-rw-r--r--src/entry.h27
-rw-r--r--src/opt.c4
4 files changed, 209 insertions, 11 deletions
diff --git a/src/calendar.h b/src/calendar.h
index 060ad99..f5f1286 100644
--- a/src/calendar.h
+++ b/src/calendar.h
@@ -1,17 +1,10 @@
#ifndef EVERY_CALENDAR_H
#define EVERY_CALENDAR_H
-enum calendar_entry_type_e {
- CALENDAR_ENTRY_TYPE_ON,
- CALENDAR_ENTRY_TYPE_EVERY,
-};
-
-struct calendar_entry_s {
- enum calendar_entry_type_e type;
-};
+#include "entry.h"
struct calendar_s {
- struct calendar_entry_s *entries;
+ struct entry_s *entries;
};
#endif
diff --git a/src/entry.c b/src/entry.c
new file mode 100644
index 0000000..64acdea
--- /dev/null
+++ b/src/entry.c
@@ -0,0 +1,178 @@
+#include "entry.h"
+
+#include <assert.h>
+
+static int sub_inc_year(struct tm *t, int n)
+{
+ if (n == 0)
+ return 0;
+
+ t->tm_year += n;
+
+ if (mktime(t) == -1)
+ return -1;
+
+ return 0;
+}
+
+static int sub_inc_month(struct tm *t, int n)
+{
+ unsigned i;
+
+ if (n == 0)
+ return 0;
+
+ for (i = 0; i < n; i++) {
+ t->tm_mon++;
+ if (mktime(t) == -1) {
+ t->tm_mon = 0;
+ if (sub_inc_year(t, 1) == -1)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int sub_inc_day(struct tm *t, int n)
+{
+ unsigned i;
+
+ if (n == 0)
+ return 0;
+
+ for (i = 0; i < n; i++) {
+ t->tm_mday++;
+ if (mktime(t) == -1) {
+ t->tm_mday = 1;
+ if (sub_inc_month(t, 1) == -1)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int sub_inc_hour(struct tm *t, int n)
+{
+ unsigned i;
+
+ if (n == 0)
+ return 0;
+
+ for (i = 0; i < n; i++) {
+ t->tm_hour++;
+ if (mktime(t) == -1) {
+ t->tm_hour = 0;
+ if (sub_inc_day(t, 1) == -1)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int sub_inc_minute(struct tm *t, int n)
+{
+ unsigned i;
+
+ if (n == 0)
+ return 0;
+
+ for (i = 0; i < n; i++) {
+ t->tm_min++;
+ if (mktime(t) == -1) {
+ t->tm_min = 0;
+ if (sub_inc_hour(t, 1) == -1)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int sub_inc_second(struct tm *t, int n)
+{
+ time_t r;
+ struct tm *tmp;
+
+ if (n == 0)
+ return 0;
+
+ r = mktime(t);
+
+ if (r + n <= r)
+ return -1;
+ r += n;
+
+ tmp = localtime(&r);
+ *t = *tmp;
+
+ return 0;
+}
+
+/* super inefficient, but should best-possible avoid any weird leap
+ * years/seconds/dst-problems/other future changes */
+bool entry_is_active(struct entry_s *e, time_t now)
+{
+ struct tm t, *tmp;
+ time_t rtmp, now_plus_warn;
+
+ assert(e != NULL);
+
+ tmp = localtime(&now);
+ assert(tmp != NULL);
+ t = *tmp;
+
+ if (sub_inc_year(&t, e->warn.year))
+ return false;
+ if (sub_inc_month(&t, e->warn.month))
+ return false;
+ if (sub_inc_day(&t, e->warn.day))
+ return false;
+ if (sub_inc_hour(&t, e->warn.hour))
+ return false;
+ if (sub_inc_minute(&t, e->warn.minute))
+ return false;
+ if (sub_inc_second(&t, e->warn.second))
+ return false;
+
+ now_plus_warn = mktime(&t);
+
+ if (e->type == ENTRY_TYPE_ON) {
+ if (e->start >= now && e->start <= now_plus_warn)
+ return true;
+
+ return false;
+ }
+
+ tmp = localtime(&(e->start));
+ assert(tmp != NULL);
+ t = *tmp;
+
+ if (e->has_end && now > e->end)
+ return false;
+
+ for (rtmp = e->start;;) {
+ rtmp = mktime(&t);
+
+ if (rtmp > now_plus_warn)
+ return false;
+
+ if (rtmp >= now)
+ return true;
+
+ if (sub_inc_year(&t, e->every.year))
+ return false;
+ if (sub_inc_month(&t, e->every.month))
+ return false;
+ if (sub_inc_day(&t, e->every.day))
+ return false;
+ if (sub_inc_hour(&t, e->every.hour))
+ return false;
+ if (sub_inc_minute(&t, e->every.minute))
+ return false;
+ if (sub_inc_second(&t, e->every.second))
+ return false;
+ }
+}
diff --git a/src/entry.h b/src/entry.h
new file mode 100644
index 0000000..1420d9b
--- /dev/null
+++ b/src/entry.h
@@ -0,0 +1,27 @@
+#ifndef EVERY_ENTRY_H
+#define EVERY_ENTRY_H
+
+#include <time.h>
+#include <stdbool.h>
+
+enum entry_type_e {
+ ENTRY_TYPE_ON,
+ ENTRY_TYPE_EVERY,
+};
+
+struct entry_interval_s {
+ int year, month, day, hour, minute, second;
+};
+
+/* type ON uses only start and warn */
+struct entry_s {
+ enum entry_type_e type;
+ bool has_end;
+ time_t start, end;
+ struct entry_interval_s every, warn;
+};
+
+/* test if an entry needs warning */
+bool entry_is_active(struct entry_s *e, time_t now);
+
+#endif
diff --git a/src/opt.c b/src/opt.c
index eebb248..31b1186 100644
--- a/src/opt.c
+++ b/src/opt.c
@@ -14,7 +14,7 @@ static struct simple_opt options[] = {
{ SIMPLE_OPT_FLAG, 'v', "version", false,
"print the version of every in use and exit" },
{ SIMPLE_OPT_STRING, 'c', "calendar", true,
- "path to calendar", "<file>" },
+ "path to calendar file", "<file>" },
{ SIMPLE_OPT_STRING, 'e', "editor", true,
"text editor for editing calendars", "<cmd>" },
{ SIMPLE_OPT_END }
@@ -35,7 +35,7 @@ void opt_parse(int argc, char **argv)
/* help */
if (options[0].was_seen) {
simple_opt_print_usage(stdout, 80, argv[0],
- "[-c CALENDAR_FILE] [-m OUTPUT_MODE]",
+ "[-c CALENDAR_FILE] [-e TEXT_EDITOR] [COMMAND]",
"every is a flexible, console-based event calendar",
options);