|
@@ -0,0 +1,369 @@
|
|
|
|
+#include <stdio.h>
|
|
|
|
+#include <string.h>
|
|
|
|
+#include <time.h>
|
|
|
|
+#include <sys/time.h>
|
|
|
|
+#include <stdlib.h>
|
|
|
|
+
|
|
|
|
+enum scales {
|
|
|
|
+ SCALE_YEAR = 0,
|
|
|
|
+ SCALE_MONTH,
|
|
|
|
+ SCALE_WEEK,
|
|
|
|
+ SCALE_MDAY,
|
|
|
|
+ SCALE_WDAY,
|
|
|
|
+ SCALE_YDAY,
|
|
|
|
+ SCALE_HOUR,
|
|
|
|
+ SCALE_MINUTE,
|
|
|
|
+ SCALE_SECOND,
|
|
|
|
+
|
|
|
|
+ SCALE_MAX
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+#define MAX_CODES 2
|
|
|
|
+#define MAX_VALUE_LEN 16 /* for spelled out month names, longest is "September" */
|
|
|
|
+
|
|
|
|
+typedef int (*scale_match_func)(const int time_var, const char *from, const char *to);
|
|
|
|
+
|
|
|
|
+struct scale_definition {
|
|
|
|
+ scale_match_func func;
|
|
|
|
+ const char *codes[MAX_CODES];
|
|
|
|
+ int flags;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+#define FLAG_INTEGER_ARGS 0x1
|
|
|
|
+
|
|
|
|
+static int year_fn(const int time_var, const char *from, const char *to);
|
|
|
|
+static int month_fn(const int time_var, const char *from, const char *to);
|
|
|
|
+static int week_fn(const int time_var, const char *from, const char *to);
|
|
|
|
+static int mday_fn(const int time_var, const char *from, const char *to);
|
|
|
|
+static int wday_fn(const int time_var, const char *from, const char *to);
|
|
|
|
+static int yday_fn(const int time_var, const char *from, const char *to);
|
|
|
|
+static int hour_fn(const int time_var, const char *from, const char *to);
|
|
|
|
+static int minute_fn(const int time_var, const char *from, const char *to);
|
|
|
|
+static int second_fn(const int time_var, const char *from, const char *to);
|
|
|
|
+
|
|
|
|
+static const struct scale_definition defs[SCALE_MAX + 1] = {
|
|
|
|
+ [SCALE_YEAR ] = { year_fn, { "year", "yr" }, FLAG_INTEGER_ARGS },
|
|
|
|
+ [SCALE_MONTH ] = { month_fn, { "month", "mo" }, 0 },
|
|
|
|
+ [SCALE_WEEK ] = { week_fn, { "week", "wk" }, FLAG_INTEGER_ARGS }, /* week of the month */
|
|
|
|
+ [SCALE_MDAY ] = { mday_fn, { "mday", "md" }, FLAG_INTEGER_ARGS }, /* day of the month */
|
|
|
|
+ [SCALE_WDAY ] = { wday_fn, { "wday", "wd" }, 0 }, /* day of the week */
|
|
|
|
+ [SCALE_YDAY ] = { yday_fn, { "yday", "yd" }, FLAG_INTEGER_ARGS }, /* day of the year */
|
|
|
|
+ [SCALE_HOUR ] = { hour_fn, { "hour", "hr" }, FLAG_INTEGER_ARGS },
|
|
|
|
+ [SCALE_MINUTE] = { minute_fn, { "minute", "min" }, FLAG_INTEGER_ARGS },
|
|
|
|
+ [SCALE_SECOND] = { second_fn, { "second", "sec" }, FLAG_INTEGER_ARGS },
|
|
|
|
+ /* XXX week of the year? */
|
|
|
|
+
|
|
|
|
+ [SCALE_MAX ] = { NULL, { NULL, } },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static const char *months[12] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug",
|
|
|
|
+ "sep", "oct", "nov", "dec" };
|
|
|
|
+static const char *weekdays[7] = { "su", "mo", "tu", "we", "th", "fr", "sa" };
|
|
|
|
+
|
|
|
|
+static void get_time_vars(int time_vars[SCALE_MAX], time_t t) {
|
|
|
|
+ struct tm tm;
|
|
|
|
+
|
|
|
|
+ localtime_r(&t, &tm);
|
|
|
|
+
|
|
|
|
+ time_vars[SCALE_YEAR] = tm.tm_year + 1900;
|
|
|
|
+ time_vars[SCALE_MONTH] = tm.tm_mon + 1;
|
|
|
|
+ time_vars[SCALE_WEEK] = (tm.tm_mday - 1 + (tm.tm_wday - tm.tm_mday + 1) % 7) / 7 + 1;
|
|
|
|
+ time_vars[SCALE_MDAY] = tm.tm_mday;
|
|
|
|
+ time_vars[SCALE_WDAY] = tm.tm_wday;
|
|
|
|
+ time_vars[SCALE_YDAY] = tm.tm_yday + 1;
|
|
|
|
+ time_vars[SCALE_HOUR] = tm.tm_hour;
|
|
|
|
+ time_vars[SCALE_MINUTE] = tm.tm_min;
|
|
|
|
+ time_vars[SCALE_SECOND] = tm.tm_sec;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#define WS_SKIP() while (*p == ' ') p++;
|
|
|
|
+
|
|
|
|
+int in_period(time_t t, const char *p) {
|
|
|
|
+ int time_vars[SCALE_MAX];
|
|
|
|
+ int scale_results[SCALE_MAX];
|
|
|
|
+ int scale, j, len, res;
|
|
|
|
+ const char *c, *a1, *a2;
|
|
|
|
+ char from[MAX_VALUE_LEN], to[MAX_VALUE_LEN], *str;
|
|
|
|
+
|
|
|
|
+ /* If no period is given or string is empty, the time always matches */
|
|
|
|
+ if (!p)
|
|
|
|
+ return 1;
|
|
|
|
+ WS_SKIP();
|
|
|
|
+ if (!*p)
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+ /* If "none" or "never" is given, time never matches */
|
|
|
|
+ if (!strcasecmp(p, "none") || !strcasecmp(p, "never"))
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ get_time_vars(time_vars, t);
|
|
|
|
+
|
|
|
|
+ /* Loop through all sub-periods, separated by commas.
|
|
|
|
+ string := PERIOD [, PERIOD ... ] */
|
|
|
|
+ while (1) {
|
|
|
|
+ memset(scale_results, -1, sizeof(scale_results));
|
|
|
|
+
|
|
|
|
+ /* Each sub-period consists of one or more scales, separated by spaces.
|
|
|
|
+ PERIOD := SCALE { VALUES } [ SCALE { VALUES } ... ] */
|
|
|
|
+ while (1) {
|
|
|
|
+ /* XXX could do some hashing here */
|
|
|
|
+ for (scale = 0; scale < SCALE_MAX; scale++) {
|
|
|
|
+ for (j = 0; j < MAX_CODES; j++) {
|
|
|
|
+ c = defs[scale].codes[j];
|
|
|
|
+ len = strlen(c);
|
|
|
|
+ if (strncasecmp(p, c, len))
|
|
|
|
+ continue;
|
|
|
|
+ if (p[len] == ' ' || p[len] == '{')
|
|
|
|
+ goto found_scale;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* No valid scale definition found, syntax error */
|
|
|
|
+ return -1;
|
|
|
|
+
|
|
|
|
+found_scale:
|
|
|
|
+ /* Skip over scale name, whitespace and brace */
|
|
|
|
+ p += len;
|
|
|
|
+ WS_SKIP();
|
|
|
|
+ if (*p != '{')
|
|
|
|
+ return -1; /* Syntax error */
|
|
|
|
+ p++;
|
|
|
|
+ WS_SKIP();
|
|
|
|
+
|
|
|
|
+ /* Keep track of what we've found */
|
|
|
|
+ if (scale_results[scale] == -1)
|
|
|
|
+ scale_results[scale] = 0;
|
|
|
|
+ else if (scale_results[scale] == 1) {
|
|
|
|
+ /* We already have a valid match for this scale. Skip
|
|
|
|
+ over all this nonsense then. */
|
|
|
|
+ while (*p && *p != '}')
|
|
|
|
+ p++;
|
|
|
|
+ if (!*p)
|
|
|
|
+ return -1; /* Syntax error */
|
|
|
|
+ goto close_brace;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* We're inside the braces now. Values are separated
|
|
|
|
+ by spaces, possibly given as ranges.
|
|
|
|
+ VALUES := ( VALUE | RANGE ) [ ( VALUE | RANGE ) ... ]
|
|
|
|
+ RANGE := VALUE - VALUE */
|
|
|
|
+
|
|
|
|
+ while (1) {
|
|
|
|
+ str = from;
|
|
|
|
+ len = sizeof(from) - 1;
|
|
|
|
+ *from = *to = '\0';
|
|
|
|
+ while (1) {
|
|
|
|
+ switch (*p) {
|
|
|
|
+ case '\0':
|
|
|
|
+ return -1; /* Syntax error */
|
|
|
|
+
|
|
|
|
+ case ' ':
|
|
|
|
+ WS_SKIP();
|
|
|
|
+ /* Here, it's either a hyphen or end of value/range */
|
|
|
|
+ if (*p == '-')
|
|
|
|
+ goto hyphen;
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case '-':
|
|
|
|
+hyphen:
|
|
|
|
+ if (!*from)
|
|
|
|
+ return -1; /* Range given as "-foo", syntax error */
|
|
|
|
+ if (*to)
|
|
|
|
+ return -1; /* Range given as "foo-bar-baz", syntax error */
|
|
|
|
+ /* Terminate "from" string and init for "to" */
|
|
|
|
+ *str = '\0';
|
|
|
|
+ str = to;
|
|
|
|
+ len = sizeof(to) - 1;
|
|
|
|
+ p++;
|
|
|
|
+ WS_SKIP();
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ case '}':
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ default:
|
|
|
|
+ /* everything else gets copied and lowercased */
|
|
|
|
+ if (len <= 0)
|
|
|
|
+ return -1; /* String too long, syntax error */
|
|
|
|
+ *str++ = *p++ | 0x20; /* works for letters and digits */
|
|
|
|
+ len--;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ *str = '\0';
|
|
|
|
+
|
|
|
|
+ /* Finished parsing out value or range. An empty result
|
|
|
|
+ is valid, e.g. at the end of the list for the scale */
|
|
|
|
+ if (!*from) {
|
|
|
|
+ if (*p == '}')
|
|
|
|
+ break;
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ a1 = from;
|
|
|
|
+ a2 = *to ? to : NULL;
|
|
|
|
+ if ((defs[scale].flags & FLAG_INTEGER_ARGS)) {
|
|
|
|
+ a1 = (void *) atol(a1);
|
|
|
|
+ a2 = (void *) (a2 ? atol(a2) : -1);
|
|
|
|
+ }
|
|
|
|
+ res = defs[scale].func(time_vars[scale], a1, a2);
|
|
|
|
+ printf("result: %i\n", res);
|
|
|
|
+
|
|
|
|
+ if (res == -1)
|
|
|
|
+ return -1; /* Syntax error */
|
|
|
|
+ else if (res == 1)
|
|
|
|
+ scale_results[scale] = 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+close_brace:
|
|
|
|
+ p++;
|
|
|
|
+
|
|
|
|
+ /* Finished with one scale, braces closed. See if there's any more */
|
|
|
|
+ WS_SKIP();
|
|
|
|
+ if (!*p || *p == ',') {
|
|
|
|
+ /* Nope! Evaluate our result */
|
|
|
|
+ for (scale = 0; scale < SCALE_MAX; scale++) {
|
|
|
|
+ if (scale_results[scale] == 0)
|
|
|
|
+ goto no_match;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* All scales that were given matched! We're done! */
|
|
|
|
+ return 1;
|
|
|
|
+
|
|
|
|
+no_match:
|
|
|
|
+ /* No luck, try next one if there are any more */
|
|
|
|
+ if (*p == ',') {
|
|
|
|
+ p++;
|
|
|
|
+ WS_SKIP();
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int generic_fn(const int time_var, const long f, long t, const long min, const long max) {
|
|
|
|
+ if (t == -1)
|
|
|
|
+ t = f;
|
|
|
|
+
|
|
|
|
+ if (f < min || f > max)
|
|
|
|
+ return -1;
|
|
|
|
+ if (t < min || t > max)
|
|
|
|
+ return -1;
|
|
|
|
+
|
|
|
|
+ if (f > t) {
|
|
|
|
+ if (f <= time_var || t >= time_var)
|
|
|
|
+ return 1;
|
|
|
|
+ }
|
|
|
|
+ else if (f <= time_var && time_var <= t)
|
|
|
|
+ return 1;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int generic_named_fn(const int time_var, const char *from, const char *to,
|
|
|
|
+ const char **array, int arr_len, int str_len) {
|
|
|
|
+
|
|
|
|
+ int i, f = 0, t = 0;
|
|
|
|
+
|
|
|
|
+ f = atoi(from);
|
|
|
|
+ if (!f)
|
|
|
|
+ for (i = 0; i < arr_len; i++)
|
|
|
|
+ if (!strncmp(array[i], from, str_len)) {
|
|
|
|
+ f = i + 1;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ if (!f)
|
|
|
|
+ return -1;
|
|
|
|
+
|
|
|
|
+ if (!to)
|
|
|
|
+ t = f;
|
|
|
|
+ else {
|
|
|
|
+ t = atoi(to);
|
|
|
|
+ if (!t)
|
|
|
|
+ for (i = 0; i < arr_len; i++)
|
|
|
|
+ if (!strncmp(array[i], to, str_len)) {
|
|
|
|
+ t = i + 1;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ if (!t)
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return generic_fn(time_var, f, t, 1, arr_len);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int year_fn(const int time_var, const char *from, const char *to) {
|
|
|
|
+ long f, t, c;
|
|
|
|
+ printf("%s %i %li %li\n", __FUNCTION__, time_var, (long) from, (long) to);
|
|
|
|
+
|
|
|
|
+ f = (long) from;
|
|
|
|
+ t = (long) to;
|
|
|
|
+
|
|
|
|
+ if (t == -1)
|
|
|
|
+ t = f;
|
|
|
|
+
|
|
|
|
+ c = time_var / 100;
|
|
|
|
+
|
|
|
|
+ if (t < 0)
|
|
|
|
+ return -1;
|
|
|
|
+ else if (t <= 99)
|
|
|
|
+ t += c;
|
|
|
|
+ else if (t < 1970)
|
|
|
|
+ return -1;
|
|
|
|
+
|
|
|
|
+ if (f < 0)
|
|
|
|
+ return -1;
|
|
|
|
+ else if (f <= 99)
|
|
|
|
+ f += c;
|
|
|
|
+ else if (f < 1970)
|
|
|
|
+ return -1;
|
|
|
|
+
|
|
|
|
+ if (time_var >= f && time_var <= t)
|
|
|
|
+ return 1;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int month_fn(const int time_var, const char *from, const char *to) {
|
|
|
|
+ printf("%s %i '%s' '%s'\n", __FUNCTION__, time_var, from, to);
|
|
|
|
+ return generic_named_fn(time_var, from, to, months, 12, 3);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int week_fn(const int time_var, const char *from, const char *to) {
|
|
|
|
+ printf("%s %i %li %li\n", __FUNCTION__, time_var, (long) from, (long) to);
|
|
|
|
+ return generic_fn(time_var, (long) from, (long) to, 1, 6);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int mday_fn(const int time_var, const char *from, const char *to) {
|
|
|
|
+ printf("%s %i %li %li\n", __FUNCTION__, time_var, (long) from, (long) to);
|
|
|
|
+ return generic_fn(time_var, (long) from, (long) to, 1, 31);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int wday_fn(const int time_var, const char *from, const char *to) {
|
|
|
|
+ printf("%s %i '%s' '%s'\n", __FUNCTION__, time_var, from, to);
|
|
|
|
+ return generic_named_fn(time_var, from, to, weekdays, 7, 2);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int yday_fn(const int time_var, const char *from, const char *to) {
|
|
|
|
+ printf("%s %i %li %li\n", __FUNCTION__, time_var, (long) from, (long) to);
|
|
|
|
+ return generic_fn(time_var, (long) from, (long) to, 1, 366);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int hour_fn(const int time_var, const char *from, const char *to) {
|
|
|
|
+ printf("%s %i %li %li\n", __FUNCTION__, time_var, (long) from, (long) to);
|
|
|
|
+ return generic_fn(time_var, (long) from, (long) to, 0, 23);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int minute_fn(const int time_var, const char *from, const char *to) {
|
|
|
|
+ printf("%s %i %li %li\n", __FUNCTION__, time_var, (long) from, (long) to);
|
|
|
|
+ return generic_fn(time_var, (long) from, (long) to, 0, 59);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int second_fn(const int time_var, const char *from, const char *to) {
|
|
|
|
+ printf("%s %i %li %li\n", __FUNCTION__, time_var, (long) from, (long) to);
|
|
|
|
+ return generic_fn(time_var, (long) from, (long) to, 0, 60); /* allow for leap seconds */
|
|
|
|
+}
|