All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
timestr.c
Go to the documentation of this file.
1 /*
2  * timestr.c See if a string like 'Su2300-0700' matches (UUCP style).
3  *
4  * Version: $Id: a1fffc6674ef528a639418b6b61c3681724b25b8 $
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000,2006 The FreeRADIUS server project
21  * Copyright 2000 Alan DeKok <aland@ox.org>
22  */
23 
24 RCSID("$Id: a1fffc6674ef528a639418b6b61c3681724b25b8 $")
25 
26 #include <freeradius-devel/radiusd.h>
27 
28 #include <ctype.h>
29 
30 int timestr_match(char const *, time_t);
31 
32 static char const *days[] =
33  { "su", "mo", "tu", "we", "th", "fr", "sa", "wk", "any", "al" };
34 
35 #define DAYMIN (24*60)
36 #define WEEKMIN (24*60*7)
37 #define val(x) (( (x) < 48 || (x) > 57) ? 0 : ((x) - 48))
38 
39 #if 0 /* Set to 1 if you're a developer and want to debug this code */
40 # define timestr_debug DEBUG2
41 # define do_timestr_debug 1
42 #else
43 # define timestr_debug if (0) printf
44 #endif
45 
46 /*
47  * String code.
48  */
49 static int strcode (char const **str)
50 {
51  int i;
52  size_t l;
53 
54  timestr_debug("strcode %s called\n", *str);
55 
56  for (i = 0; i < 10; i++) {
57  l = strlen(days[i]);
58  if (l > strlen(*str))
59  continue;
60  if (strncmp(*str, days[i], l) == 0) {
61  *str += l;
62  break;
63  }
64  }
65  timestr_debug("strcode result %d\n", i);
66 
67  return (i >= 10) ? -1 : i;
68 
69 }
70 
71 /*
72  * Fill bitmap with hours/mins.
73  */
74 static int hour_fill(char *bitmap, char const *tm)
75 {
76  char *p;
77  int start, end;
78  int i, bit, byte;
79 
80  timestr_debug("hour_fill called for %s\n", tm);
81 
82  /*
83  * Get timerange in start and end.
84  */
85  end = -1;
86  if ((p = strchr(tm, '-')) != NULL) {
87  p++;
88  if (p - tm != 5 || strlen(p) < 4 || !isdigit((int) *p))
89  return 0;
90  end = 600 * val(p[0]) + 60 * val(p[1]) + atoi(p + 2);
91  }
92  if (*tm == 0) {
93  start = 0;
94  end = DAYMIN - 1;
95  } else {
96  if (strlen(tm) < 4 || !isdigit((int) *tm))
97  return 0;
98  start = 600 * val(tm[0]) + 60 * val(tm[1]) + atoi(tm + 2);
99  if (end < 0) end = start;
100  }
101  /* Treat 2400 as 0000, and do some more silent error checks. */
102  if (end < 0) end = 0;
103  if (start < 0) start = 0;
104  if (end >= DAYMIN) end = DAYMIN - 1;
105  if (start >= DAYMIN) start = DAYMIN - 1;
106 
107  timestr_debug("hour_fill: range from %d to %d\n", start, end);
108 
109  /*
110  * Fill bitmap.
111  */
112  i = start;
113  while (1) {
114  byte = (i / 8);
115  bit = i % 8;
116  timestr_debug("setting byte %d, bit %d\n", byte, bit);
117  bitmap[byte] |= (1 << bit);
118  if (i == end) break;
119  i++;
120  i %= DAYMIN;
121  }
122  return 1;
123 }
124 
125 /*
126  * Call the fill bitmap function for every day listed.
127  */
128 static int day_fill(char *bitmap, char const *tm)
129 {
130  char const *hr;
131  int n;
132  int start, end;
133 
134  for (hr = tm; *hr; hr++)
135  if (isdigit((int) *hr))
136  break;
137  if (hr == tm)
138  tm = "Al";
139 
140  timestr_debug("dayfill: hr %s tm %s\n", hr, tm);
141 
142  while ((start = strcode(&tm)) >= 0) {
143  /*
144  * Find start and end weekdays and
145  * build a valid range 0 - 6.
146  */
147  if (*tm == '-') {
148  tm++;
149  if ((end = strcode(&tm)) < 0)
150  break;
151  } else
152  end = start;
153  if (start == 7) {
154  start = 1;
155  end = 5;
156  }
157  if (start > 7) {
158  start = 0;
159  end = 6;
160  }
161  n = start;
162  timestr_debug("day_fill: range from %d to %d\n", start, end);
163  while (1) {
164  hour_fill(bitmap + 180 * n, hr);
165  if (n == end) break;
166  n++;
167  n %= 7;
168  }
169  }
170 
171  return 1;
172 }
173 
174 /*
175  * Fill the week bitmap with allowed times.
176  */
177 static int week_fill(char *bitmap, char const *tm)
178 {
179  char *s;
180  char tmp[256];
181 
182  strlcpy(tmp, tm, sizeof(tmp));
183  for (s = tmp; *s; s++)
184  if (isupper(*s)) *s = tolower(*s);
185 
186  s = strtok(tmp, ",|");
187  while (s) {
188  day_fill(bitmap, s);
189  s = strtok(NULL, ",|");
190  }
191 
192  return 0;
193 }
194 
195 /*
196  * Match a timestring and return seconds left.
197  * -1 for no match, 0 for unlimited.
198  */
199 int timestr_match(char const *tmstr, time_t t)
200 {
201  struct tm *tm, s_tm;
202  char bitmap[WEEKMIN / 8];
203  int now, tot, i;
204  int byte, bit;
205 #ifdef do_timestr_debug
206  int y;
207  char *s;
208  char null[8];
209 #endif
210 
211  tm = localtime_r(&t, &s_tm);
212  now = tm->tm_wday * DAYMIN + tm->tm_hour * 60 + tm->tm_min;
213  tot = 0;
214  memset(bitmap, 0, sizeof(bitmap));
215  week_fill(bitmap, tmstr);
216 
217 #ifdef do_timestr_debug
218  memset(null, 0, 8);
219  for (i = 0; i < 7; i++) {
220  timestr_debug("%d: ", i);
221  s = bitmap + 180 * i;
222  for (y = 0; y < 23; y++) {
223  s = bitmap + 180 * i + (75 * y) / 10;
224  timestr_debug("%c", memcmp(s, null, 8) == 0 ? '.' : '#');
225  }
226  timestr_debug("\n");
227  }
228 #endif
229 
230  /*
231  * See how many minutes we have.
232  */
233  i = now;
234  while (1) {
235  byte = i / 8;
236  bit = i % 8;
237  timestr_debug("READ: checking byte %d bit %d\n", byte, bit);
238  if (!(bitmap[byte] & (1 << bit)))
239  break;
240  tot += 60;
241  i++;
242  i %= WEEKMIN;
243  if (i == now)
244  break;
245  }
246 
247  if (tot == 0)
248  return -1;
249 
250  return (i == now) ? 0 : tot;
251 }
252 
253 #ifdef STANDALONE
254 
255 int main(int argc, char **argv)
256 {
257  int l;
258 
259  if (argc != 2) {
260  fprintf(stderr, "Usage: test timestring\n");
261  exit(1);
262  }
263  l = timestr_match(argv[1], time(NULL));
264  printf ("%s: %d seconds left\n", argv[1], l);
265  return 0;
266 }
267 
268 #endif
269 
static int week_fill(char *bitmap, char const *tm)
Definition: timestr.c:177
static char const * days[]
Definition: timestr.c:32
#define WEEKMIN
Definition: timestr.c:36
#define DAYMIN
Definition: timestr.c:35
static int hour_fill(char *bitmap, char const *tm)
Definition: timestr.c:74
#define timestr_debug
Definition: timestr.c:43
#define val(x)
Definition: timestr.c:37
static int day_fill(char *bitmap, char const *tm)
Definition: timestr.c:128
static int strcode(char const **str)
Definition: timestr.c:49
int main(int argc, char *argv[])
Definition: radattr.c:959
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition: strlcpy.c:38
struct tm * localtime_r(time_t const *l_clock, struct tm *result)
Definition: missing.c:152
#define RCSID(id)
Definition: build.h:135
int timestr_match(char const *, time_t)
Definition: timestr.c:199