mirror of https://github.com/sipwise/kamailio.git
parent
70833b5964
commit
902c679f71
@ -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 */
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
#ifndef _PERIOD_H_
|
||||
#define _PERIOH_H_
|
||||
|
||||
int in_period(time_t t, const char *p);
|
||||
|
||||
#endif
|
||||
Loading…
Reference in new issue