Initial revision
[freeradius.git] / src / main / timestr.c
1 /*
2  * timestr.c    See if a string like 'Su2300-0700' matches (UUCP style).
3  *
4  * Version:     @(#)timestr.c  0.10  21-Mar-1999 miquels@cistron.nl
5  *
6  */
7
8 #include        "autoconf.h"
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <time.h>
14 #include <ctype.h>
15
16 static char *days[] =
17         { "su", "mo", "tu", "we", "th", "fr", "sa", "wk", "any", "al" };
18
19 #define DAYMIN          (24*60)
20 #define WEEKMIN         (24*60*7)
21 #define val(x)          (( (x) < 48 || (x) > 57) ? 0 : ((x) - 48))
22
23 #ifdef DEBUG
24 #  define xprintf if (1) printf
25 #else
26 #  define xprintf if (0) printf
27 #endif
28
29 /*
30  *      String code.
31  */
32 static int strcode (char **str)
33 {
34         int             i, l;
35
36         xprintf("strcode %s called\n", *str);
37
38         for (i = 0; i < 10; i++) {
39                 l = strlen(days[i]);
40                 if (l > strlen(*str))
41                         continue;
42                 if (strncmp(*str, days[i], l) == 0) {
43                         *str += l;
44                         break;
45                 }
46         }
47         xprintf("strcode result %d\n", i);
48
49         return (i >= 10) ? -1 : i;
50
51 }
52
53 /*
54  *      Fill bitmap with hours/mins.
55  */
56 static int hour_fill(char *bitmap, char *tm)
57 {
58         char            *p;
59         int             start, end;
60         int             i, bit, byte;
61
62         xprintf("hour_fill called for %s\n", tm);
63
64         /*
65          *      Get timerange in start and end.
66          */
67         end = -1;
68         if ((p = strchr(tm, '-')) != NULL) {
69                 p++;
70                 if (p - tm != 5 || strlen(p) < 4 || !isdigit(*p))
71                         return 0;
72                 end = 600 * val(p[0]) + 60 * val(p[1]) + atoi(p + 2);
73         }
74         if (*tm == 0) {
75                 start = 0;
76                 end = DAYMIN - 1;
77         } else {
78                 if (strlen(tm) < 4 || !isdigit(*tm))
79                         return 0;
80                 start = 600 * val(tm[0]) + 60 * val(tm[1]) + atoi(tm + 2);
81                 if (end < 0) end = start;
82         }
83         /* Treat 2400 as 0000, and do some more silent error checks. */
84         if (end < 0)   end = 0;
85         if (start < 0) start = 0;
86         if (end >= DAYMIN)   end = DAYMIN - 1;
87         if (start >= DAYMIN) start = DAYMIN - 1;
88
89         xprintf("hour_fill: range from %d to %d\n", start, end);
90
91         /*
92          *      Fill bitmap.
93          */
94         i = start;
95         while (1) {
96                 byte = (i / 8);
97                 bit  = i % 8;
98                 xprintf("setting byte %d, bit %d\n", byte, bit);
99                 bitmap[byte] |= (1 << bit);
100                 if (i == end) break;
101                 i++;
102                 i %= DAYMIN;
103         }
104         return 1;
105 }
106
107 /*
108  *      Call the fill bitmap function for every day listed.
109  */
110 static int day_fill(char *bitmap, char *tm)
111 {
112         char            *hr;
113         int             n;
114         int             start, end;
115
116         for (hr = tm; *hr; hr++)
117                 if (isdigit(*hr))
118                         break;
119         if (hr == tm) tm = "Al";
120
121         xprintf("dayfill: hr %s    tm %s\n", hr, tm);
122
123         while ((start = strcode(&tm)) >= 0) {
124                 /*
125                  *      Find start and end weekdays and
126                  *      build a valid range 0 - 6.
127                  */
128                 if (*tm == '-') {
129                         tm++;
130                         if ((end = strcode(&tm)) < 0)
131                                 break;
132                 } else
133                         end = start;
134                 if (start == 7) {
135                         start = 1;
136                         end = 5;
137                 }
138                 if (start > 7) {
139                         start = 0;
140                         end = 6;
141                 }
142                 n = start;
143                 xprintf("day_fill: range from %d to %d\n", start, end);
144                 while (1) {
145                         hour_fill(bitmap + 180 * n, hr);
146                         if (n == end) break;
147                         n++;
148                         n %= 7;
149                 }
150         }
151
152         return 1;
153 }
154
155 /*
156  *      Fill the week bitmap with allowed times.
157  */
158 static int week_fill(char *bitmap, char *tm)
159 {
160         char            *s;
161         char            tmp[128];
162
163         strncpy(tmp, tm, 128);
164         tmp[127] = 0;
165         for (s = tmp; *s; s++)
166                 if (isupper(*s)) *s = tolower(*s);
167
168         s = strtok(tmp, ",|");
169         while (s) {
170                 day_fill(bitmap, s);
171                 s = strtok(NULL, ",|");
172         }
173
174         return 0;
175 }
176
177 /*
178  *      Match a timestring and return seconds left.
179  *      -1 for no match, 0 for unlimited.
180  */
181 int timestr_match(char *tmstr, time_t t)
182 {
183         struct tm       *tm;
184         char            bitmap[WEEKMIN / 8];
185         int             now, tot, i;
186         int             byte, bit;
187 #if DEBUG2
188         int             y;
189         char            *s;
190         char            null[8];
191 #endif
192
193         tm = localtime(&t);
194         now = tm->tm_wday * DAYMIN + tm->tm_hour * 60 + tm->tm_min;
195         tot = 0;
196         memset(bitmap, 0, sizeof(bitmap));
197         week_fill(bitmap, tmstr);
198
199 #if DEBUG2
200         memset(null, 0, 8);
201         for (i = 0; i < 7; i++) {
202                 printf("%d: ", i);
203                 s = bitmap + 180 * i;
204                 for (y = 0; y < 23; y++) {
205                         s = bitmap + 180 * i + (75 * y) / 10;
206                         printf("%c", memcmp(s, null, 8) == 0 ? '.' : '#');
207                 }
208                 printf("\n");
209         }
210 #endif
211
212         /*
213          *      See how many minutes we have.
214          */
215         i = now;
216         while (1) {
217                 byte = i / 8;
218                 bit = i % 8;
219                 xprintf("READ: checking byte %d bit %d\n", byte, bit);
220                 if (!(bitmap[byte] & (1 << bit)))
221                         break;
222                 tot += 60;
223                 i++;
224                 i %= WEEKMIN;
225                 if (i == now)
226                         break;
227         }
228
229         if (!tot) return -1;
230         return (i == now) ? 0 : tot;
231 }
232
233 #ifdef STANDALONE
234
235 int main(int argc, char **argv)
236 {
237         int             l;
238
239         if (argc != 2) {
240                 fprintf(stderr, "Usage: test timestring\n");
241                 exit(1);
242         }
243         l = timestr_match(argv[1], time(NULL));
244         printf ("%s: %d seconds left\n", argv[1], l);
245         return 0;
246 }
247
248 #endif
249