Add a port of Time::Period

3.1
Richard Fuchs 14 years ago
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

@ -33,6 +33,7 @@
#include "../../pvar.h"
#include "../../mod_fix.h"
#include "../../lib/srutils/tmrec.h"
#include "period.h"
MODULE_VERSION
@ -45,6 +46,8 @@ static int w_tmrec_match(struct sip_msg* msg, char* rec, char* t);
static int fixup_tmrec_match(void** param, int param_no);
static int w_is_leap_year(struct sip_msg* msg, char* t, char* p2);
static int fixup_is_leap_year(void** param, int param_no);
static int fixup_time_period_match(void** param, int param_no);
static int w_time_period_match(struct sip_msg* msg, char* period, char* t);
int tmrec_wday = 0;
char tmrec_separator = '|';
@ -59,6 +62,10 @@ static cmd_export_t cmds[]={
0, ANY_ROUTE},
{"is_leap_year", (cmd_function)w_is_leap_year, 1, fixup_is_leap_year,
0, ANY_ROUTE},
{"time_period_match", (cmd_function)w_time_period_match, 1, fixup_time_period_match,
0, ANY_ROUTE},
{"time_period_match", (cmd_function)w_time_period_match, 2, fixup_time_period_match,
0, ANY_ROUTE},
{0, 0, 0, 0, 0, 0}
};
@ -220,3 +227,49 @@ static int fixup_tmrec_match(void** param, int param_no)
}
return 0;
}
static int fixup_time_period_match(void** param, int param_no)
{
if(param_no==1)
{
if(fixup_spve_null(param, 1)<0)
return -1;
return 0;
} else if(param_no==2) {
if(fixup_igp_null(param, 1)<0)
return -1;
}
return 0;
}
static int w_time_period_match(struct sip_msg* msg, char* period, char* t)
{
str rv;
time_t tv;
int ti;
if(msg==NULL)
return -1;
if(fixup_get_svalue(msg, (gparam_t*)period, &rv)!=0)
{
LM_ERR("invalid period parameter value\n");
return -1;
}
if(t!=NULL)
{
if(fixup_get_ivalue(msg, (gparam_t*)t, &ti)!=0)
{
LM_ERR("invalid time stamp parameter value\n");
return -1;
}
tv = (time_t)ti;
} else {
tv = time(NULL);
}
if (in_period(tv, rv.s))
return 1;
return 0;
}

Loading…
Cancel
Save