]> git.pond.sub.org Git - empserver/blob - src/lib/common/hours.c
Update copyright notice.
[empserver] / src / lib / common / hours.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2004, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
23  *  related information and legal notices. It is expected that any future
24  *  projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  hours.c: Game hours determination; is it legal to play now?
29  * 
30  *  Known contributors to this file:
31  *     Dave Pare, 1989
32  *     Doug Hay, 1998
33  *     Steve McClure, 1998
34  */
35
36 #include <limits.h>
37 #include <time.h>
38 #include "misc.h"
39 #include "optlist.h"
40
41 static char *weekday(char *str, int *wday);
42 static char *daytime(char *str, int *min);
43 static char *daytime_range(char *str, int *from_min, int *to_min);
44
45 /*
46  * Is week day WDAY (Sunday is 0) allowed by restriction DAYS?
47  * If DAYS is not empty, it lists the allowed week day names.  See
48  * weekday() for syntax.
49  */
50 int
51 is_wday_allowed(int wday, char *days)
52 {
53     int wd;
54
55     if (!days || !*days)
56         return 1;
57
58     while (NULL != (days = weekday(days, &wd)))
59         if (wd == wday)
60             return 1;
61
62     return 0;
63 }
64
65 /*
66  * Is day time DTIME (minutes since midnight) allowed by restriction TIMES?
67  * If TIMES is not empty, it lists the allowed day time ranges.  See
68  * daytime_range() for syntax.
69  */
70 int
71 is_daytime_allowed(int dtime, char *times)
72 {
73     int from, to;
74
75     if (!times || !*times)
76         return 1;
77
78     while (NULL != (times = daytime_range(times, &from, &to)))
79         if (from <= dtime && dtime < to)
80             return 1;
81
82     return 0;
83 }
84
85 /*
86  * Can the game played at time T?
87  */
88 int
89 gamehours(time_t t)
90 {
91     struct tm *tm;
92
93     tm = localtime(&t);
94     if (!is_wday_allowed(tm->tm_wday, game_days))
95         return 0;
96     return is_daytime_allowed(60 * tm->tm_hour + tm->tm_min, game_hours);
97 }
98
99 /*
100  * Is day time DTIME (minutes since midnight) near a time in TIMES?
101  * TIMES is a list of day times.  See daytime() for syntax.
102  * DTIME is near a listed time T if its within T and T + SLOP minutes.
103  */
104 int
105 is_daytime_near(int dtime, char *times, int slop)
106 {
107     int dt;
108
109     if (times)
110         while (NULL != (times = daytime(times, &dt)))
111             if (dt <= dtime && dtime < dt + slop)
112                 return 1;
113
114     return 0;
115 }
116
117 /*
118  * Return time in minutes between DTIME and next time in TIMES.
119  * If TIMES doesn't give a time, return -1.
120  * DTIME is day time in minutes since midnight.
121  * TIMES is a list of day times.  See daytime() for syntax.
122  */
123 int
124 min_to_next_daytime(int dtime, char *times)
125 {
126     int mindt = INT_MAX;
127     int dt;
128
129     if (times) {
130         while (NULL != (times = daytime(times, &dt))) {
131             if (dt <= dtime)
132                 dt += 24 * 60;  /* tomorrow */
133             if (dt < mindt)
134                 mindt = dt;
135         }
136     }
137
138     if (mindt == INT_MAX)
139         return -1;
140     return mindt - dtime;
141 }
142
143 /*
144  * Parse weekday name in STR.
145  * On success assign day number (Sunday is 0) to *WDAY and return
146  * pointer to first character not parsed.
147  * Else return NULL.
148  * Abbreviated names are recognized, but not single characters.
149  * Initial whitespace is ignored.
150  */
151 static char *
152 weekday(char *str, int *wday)
153 {
154     /*
155      * strptime() format " %a" would do fine, but it's XPG and Windows
156      * doesn't have it.  Besides, Empire accepts more abbreviations.
157      */
158     static char *day_name[7] = {
159         "sunday", "monday", "tuesday", "wednesday",
160         "thursday", "friday", "saturday" };
161     int i, j;
162
163     for (; isspace(*str); ++str) ;
164
165     for (i = 0; i < 7; ++i) {
166         j = 0;
167         while (str[j] && tolower(str[j]) == day_name[i][j])
168             ++j;
169         if (j > 1) {
170             *wday = i;
171             return str + j;
172         }
173     }
174
175     return NULL;
176 }
177
178 /*
179  * Parse day time in STR.
180  * On success store minutes since midnight in *MIN and return pointer
181  * to first character not parsed.
182  * Else return NULL.
183  * Time format is HOUR:MINUTE.  Initial whitespace is ignored.
184  */
185 char *
186 daytime(char *str, int *min)
187 {
188     /*
189      * strptime() format " %H:%M" would do fine, but it's XPG and
190      * Windows doesn't have it.
191      */
192     char *end;
193     unsigned long h, m;
194
195     h = strtoul(str, &end, 10);
196     if (end == str || h > 23)
197         return NULL;
198
199     if (*end++ != ':')
200         return NULL;
201
202     str = end;
203     m = strtoul(str, &end, 10);
204     if (end == str || m > 59)
205         return NULL;
206
207     *min = 60 * h + m;
208     return end;
209 }
210
211 /*
212  * Parse a day time range in STR.
213  * On success store minutes since midnight in *FROM and *TO, return
214  * pointer to first character not parsed.
215  * Else return NULL.
216  * Format is HOUR:MINUTE-HOUR:MINUTE.  Initial whitespace is ignored.
217  */
218 char *
219 daytime_range(char *str, int *from_min, int *to_min)
220 {
221     char *end;
222
223     end = daytime(str, from_min);
224     if (!end)
225         return NULL;
226     while (isspace(*end)) ++end;
227     if (*end++ != '-')
228         return NULL;
229     return daytime(end, to_min);
230 }