From 7b6c46a6d4091f82acf205ff84044d11f5c0c488 Mon Sep 17 00:00:00 2001 From: Mark Spencer Date: Thu, 12 Jan 2006 17:27:38 +0000 Subject: Merge rizzo's range optimizations (bug #6101) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@8016 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- pbx.c | 257 +++++++++++++++++++++--------------------------------------------- 1 file changed, 83 insertions(+), 174 deletions(-) (limited to 'pbx.c') diff --git a/pbx.c b/pbx.c index 4986c6209..8c12d556e 100644 --- a/pbx.c +++ b/pbx.c @@ -3693,13 +3693,70 @@ int ast_context_add_include(const char *context, const char *include, const char return -1; } -#define FIND_NEXT \ -do { \ - c = info; \ - while(*c && (*c != '|')) c++; \ - if (*c) { *c = '\0'; c++; } else c = NULL; \ -} while(0) +/*! \brief Helper for get_range. + * return the index of the matching entry, starting from 1. + * If names is not supplied, try numeric values. + */ +static int lookup_name(const char *s, char *const names[], int max) +{ + int i; + + if (names) { + for (i = 0; names[i]; i++) { + if (!strcasecmp(s, names[i])) + return i+1; + } + } else if (sscanf(s, "%d", &i) == 1 && i >= 1 && i <= max) { + return i; + } + return 0; /* error return */ +} + +/*! \brief helper function to return a range up to max (7, 12, 31 respectively). + * names, if supplied, is an array of names that should be mapped to numbers. + */ +static unsigned get_range(char *src, int max, char *const names[], const char *msg) +{ + int s, e; /* start and ending position */ + unsigned int mask = 0; + + /* Check for whole range */ + if (ast_strlen_zero(src) || !strcmp(src, "*")) { + s = 0; + e = max - 1; + } else { + /* Get start and ending position */ + char *c = strchr(src, '-'); + if (c) + *c++ = '\0'; + /* Find the start */ + s = lookup_name(src, names, max); + if (!s) { + ast_log(LOG_WARNING, "Invalid %s '%s', assuming none\n", msg, src); + return 0; + } + s--; + if (c) { /* find end of range */ + e = lookup_name(c, names, max); + if (!e) { + ast_log(LOG_WARNING, "Invalid end %s '%s', assuming none\n", msg, c); + return 0; + } + e--; + } else + e = s; + } + /* Fill the mask. Remember that ranges are cyclic */ + mask = 1 << s; /* last element in case s == e */ + for ( ; s!=e; s++) { + if (s == max) + s = 0 ; + mask |= (1 << s); + } + return mask; +} +/*! \brief store a bitmask of valid times, one bit each 2 minute */ static void get_timerange(struct ast_timing *i, char *times) { char *e; @@ -3711,10 +3768,11 @@ static void get_timerange(struct ast_timing *i, char *times) /* start disabling all times, fill the fields with 0's, as they may contain garbage */ memset(i->minmask, 0, sizeof(i->minmask)); + /* 2-minutes per bit, since the mask has only 32 bits :( */ /* Star is all times */ if (ast_strlen_zero(times) || !strcmp(times, "*")) { for (x=0; x<24; x++) - i->minmask[x] = (1 << 30) - 1; + i->minmask[x] = 0x3fffffff; /* 30 bits */ return; } /* Otherwise expect a range */ @@ -3723,8 +3781,8 @@ static void get_timerange(struct ast_timing *i, char *times) ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n"); return; } - *e = '\0'; - e++; + *e++ = '\0'; + /* XXX why skip non digits ? */ while (*e && !isdigit(*e)) e++; if (!*e) { @@ -3739,7 +3797,7 @@ static void get_timerange(struct ast_timing *i, char *times) ast_log(LOG_WARNING, "%s isn't a time. Assuming no restrictions based on time.\n", e); return; } - + /* XXX this needs to be optimized */ #if 1 s1 = s1 * 30 + s2/2; if ((s1 < 0) || (s1 >= 24*30)) { @@ -3793,99 +3851,9 @@ static char *days[] = "thu", "fri", "sat", + NULL, }; -/*! \brief get_dow: Get day of week */ -static unsigned int get_dow(char *dow) -{ - char *c; - /* The following line is coincidence, really! */ - int s, e, x; - unsigned int mask; - - /* Check for all days */ - if (ast_strlen_zero(dow) || !strcmp(dow, "*")) - return (1 << 7) - 1; - /* Get start and ending days */ - c = strchr(dow, '-'); - if (c) { - *c = '\0'; - c++; - } else - c = NULL; - /* Find the start */ - s = 0; - while((s < 7) && strcasecmp(dow, days[s])) s++; - if (s >= 7) { - ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow); - return 0; - } - if (c) { - e = 0; - while((e < 7) && strcasecmp(c, days[e])) e++; - if (e >= 7) { - ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c); - return 0; - } - } else - e = s; - mask = 0; - for (x=s; x != e; x = (x + 1) % 7) { - mask |= (1 << x); - } - /* One last one */ - mask |= (1 << x); - return mask; -} - -static unsigned int get_day(char *day) -{ - char *c; - /* The following line is coincidence, really! */ - int s, e, x; - unsigned int mask; - - /* Check for all days */ - if (ast_strlen_zero(day) || !strcmp(day, "*")) { - mask = (1 << 30) + ((1 << 30) - 1); - return mask; - } - /* Get start and ending days */ - c = strchr(day, '-'); - if (c) { - *c = '\0'; - c++; - } - /* Find the start */ - if (sscanf(day, "%d", &s) != 1) { - ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day); - return 0; - } - if ((s < 1) || (s > 31)) { - ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day); - return 0; - } - s--; - if (c) { - if (sscanf(c, "%d", &e) != 1) { - ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c); - return 0; - } - if ((e < 1) || (e > 31)) { - ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c); - return 0; - } - e--; - } else - e = s; - mask = 0; - for (x=s; x!=e; x = (x + 1) % 31) { - mask |= (1 << x); - } - mask |= (1 << x); - return mask; -} - static char *months[] = { "jan", @@ -3900,54 +3868,13 @@ static char *months[] = "oct", "nov", "dec", + NULL, }; -static unsigned int get_month(char *mon) -{ - char *c; - /* The following line is coincidence, really! */ - int s, e, x; - unsigned int mask; - - /* Check for all days */ - if (ast_strlen_zero(mon) || !strcmp(mon, "*")) - return (1 << 12) - 1; - /* Get start and ending days */ - c = strchr(mon, '-'); - if (c) { - *c = '\0'; - c++; - } - /* Find the start */ - s = 0; - while((s < 12) && strcasecmp(mon, months[s])) s++; - if (s >= 12) { - ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", mon); - return 0; - } - if (c) { - e = 0; - while((e < 12) && strcasecmp(mon, months[e])) e++; - if (e >= 12) { - ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", c); - return 0; - } - } else - e = s; - mask = 0; - for (x=s; x!=e; x = (x + 1) % 12) { - mask |= (1 << x); - } - /* One last one */ - mask |= (1 << x); - return mask; -} - int ast_build_timing(struct ast_timing *i, char *info_in) { char info_save[256]; char *info; - char *c; /* Check for empty just in case */ if (ast_strlen_zero(info_in)) @@ -3956,48 +3883,30 @@ int ast_build_timing(struct ast_timing *i, char *info_in) ast_copy_string(info_save, info_in, sizeof(info_save)); info = info_save; /* Assume everything except time */ - i->monthmask = (1 << 12) - 1; - i->daymask = (1 << 30) - 1 + (1 << 30); - i->dowmask = (1 << 7) - 1; - /* Avoid using str tok */ - FIND_NEXT; - /* Info has the time range, start with that */ - get_timerange(i, info); - info = c; - if (!info) - return 1; - FIND_NEXT; - /* Now check for day of week */ - i->dowmask = get_dow(info); - - info = c; - if (!info) - return 1; - FIND_NEXT; - /* Now check for the day of the month */ - i->daymask = get_day(info); - info = c; - if (!info) - return 1; - FIND_NEXT; - /* And finally go for the month */ - i->monthmask = get_month(info); - + i->monthmask = 0xfff; /* 12 bits */ + i->daymask = 0x7fffffffU; /* 31 bits */ + i->dowmask = 0x7f; /* 7 bits */ + /* on each call, use strsep() to move info to the next argument */ + get_timerange(i, strsep(&info, "|")); + if (info) + i->dowmask = get_range(strsep(&info, "|"), 7, days, "day of week"); + if (info) + i->daymask = get_range(strsep(&info, "|"), 31, NULL, "day"); + if (info) + i->monthmask = get_range(strsep(&info, "|"), 12, months, "month"); return 1; } int ast_check_timing(struct ast_timing *i) { struct tm tm; - time_t t; + time_t t = time(NULL); - time(&t); localtime_r(&t,&tm); /* If it's not the right month, return */ - if (!(i->monthmask & (1 << tm.tm_mon))) { + if (!(i->monthmask & (1 << tm.tm_mon))) return 0; - } /* If it's not that time of the month.... */ /* Warning, tm_mday has range 1..31! */ -- cgit v1.2.3