ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/thttpd/tdate_parse.c
Revision: 1.1
Committed: Mon Jun 18 21:11:57 2001 UTC (22 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: mp_j, dp_j, cp_j, HEAD
Branch point for: connpatch, dirpatch, mmapppatch
Log Message:
*** empty log message ***

File Contents

# Content
1 /* tdate_parse - parse string dates into internal form, stripped-down version
2 **
3 ** Copyright © 1995 by Jef Poskanzer <jef@acme.com>.
4 ** All rights reserved.
5 **
6 ** Redistribution and use in source and binary forms, with or without
7 ** modification, are permitted provided that the following conditions
8 ** are met:
9 ** 1. Redistributions of source code must retain the above copyright
10 ** notice, this list of conditions and the following disclaimer.
11 ** 2. Redistributions in binary form must reproduce the above copyright
12 ** notice, this list of conditions and the following disclaimer in the
13 ** documentation and/or other materials provided with the distribution.
14 **
15 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 ** SUCH DAMAGE.
26 */
27
28 /* This is a stripped-down version of date_parse.c, available at
29 ** http://www.acme.com/software/date_parse/
30 */
31
32 #include <sys/types.h>
33
34 #include <ctype.h>
35 #ifdef HAVE_MEMORY_H
36 #include <memory.h>
37 #endif
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <time.h>
42
43 #include "tdate_parse.h"
44
45
46 struct strlong {
47 char* s;
48 long l;
49 };
50
51
52 static void
53 pound_case( char* str )
54 {
55 for ( ; *str != '\0'; ++str )
56 {
57 if ( isupper( (int) *str ) )
58 *str = tolower( (int) *str );
59 }
60 }
61
62 static int
63 strlong_compare( v1, v2 )
64 char* v1;
65 char* v2;
66 {
67 return strcmp( ((struct strlong*) v1)->s, ((struct strlong*) v2)->s );
68 }
69
70
71 static int
72 strlong_search( char* str, struct strlong* tab, int n, long* lP )
73 {
74 int i, h, l, r;
75
76 l = 0;
77 h = n - 1;
78 for (;;)
79 {
80 i = ( h + l ) / 2;
81 r = strcmp( str, tab[i].s );
82 if ( r < 0 )
83 h = i - 1;
84 else if ( r > 0 )
85 l = i + 1;
86 else
87 {
88 *lP = tab[i].l;
89 return 1;
90 }
91 if ( h < l )
92 return 0;
93 }
94 }
95
96
97 static int
98 scan_wday( char* str_wday, long* tm_wdayP )
99 {
100 static struct strlong wday_tab[] = {
101 { "sun", 0 }, { "sunday", 0 },
102 { "mon", 1 }, { "monday", 1 },
103 { "tue", 2 }, { "tuesday", 2 },
104 { "wed", 3 }, { "wednesday", 3 },
105 { "thu", 4 }, { "thursday", 4 },
106 { "fri", 5 }, { "friday", 5 },
107 { "sat", 6 }, { "saturday", 6 },
108 };
109 static int sorted = 0;
110
111 if ( ! sorted )
112 {
113 (void) qsort(
114 wday_tab, sizeof(wday_tab)/sizeof(struct strlong),
115 sizeof(struct strlong), strlong_compare );
116 sorted = 1;
117 }
118 pound_case( str_wday );
119 return strlong_search(
120 str_wday, wday_tab, sizeof(wday_tab)/sizeof(struct strlong), tm_wdayP );
121 }
122
123
124 static int
125 scan_mon( char* str_mon, long* tm_monP )
126 {
127 static struct strlong mon_tab[] = {
128 { "jan", 0 }, { "january", 0 },
129 { "feb", 1 }, { "february", 1 },
130 { "mar", 2 }, { "march", 2 },
131 { "apr", 3 }, { "april", 3 },
132 { "may", 4 },
133 { "jun", 5 }, { "june", 5 },
134 { "jul", 6 }, { "july", 6 },
135 { "aug", 7 }, { "august", 7 },
136 { "sep", 8 }, { "september", 8 },
137 { "oct", 9 }, { "october", 9 },
138 { "nov", 10 }, { "november", 10 },
139 { "dec", 11 }, { "december", 11 },
140 };
141 static int sorted = 0;
142
143 if ( ! sorted )
144 {
145 (void) qsort(
146 mon_tab, sizeof(mon_tab)/sizeof(struct strlong),
147 sizeof(struct strlong), strlong_compare );
148 sorted = 1;
149 }
150 pound_case( str_mon );
151 return strlong_search(
152 str_mon, mon_tab, sizeof(mon_tab)/sizeof(struct strlong), tm_monP );
153 }
154
155
156 static int
157 is_leap( int year )
158 {
159 return year % 400? ( year % 100 ? ( year % 4 ? 0 : 1 ) : 0 ) : 1;
160 }
161
162
163 /* Basically the same as mktime(). */
164 static time_t
165 tm_to_time( struct tm* tmP )
166 {
167 time_t t;
168 static int monthtab[12] = {
169 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
170
171 /* Years since epoch, converted to days. */
172 t = ( tmP->tm_year - 70 ) * 365;
173 /* Leap days for previous years. */
174 t += ( tmP->tm_year - 69 ) / 4;
175 /* Days for the beginning of this month. */
176 t += monthtab[tmP->tm_mon];
177 /* Leap day for this year. */
178 if ( tmP->tm_mon >= 2 && is_leap( tmP->tm_year + 1900 ) )
179 ++t;
180 /* Days since the beginning of this month. */
181 t += tmP->tm_mday - 1; /* 1-based field */
182 /* Hours, minutes, and seconds. */
183 t = t * 24 + tmP->tm_hour;
184 t = t * 60 + tmP->tm_min;
185 t = t * 60 + tmP->tm_sec;
186
187 return t;
188 }
189
190
191 time_t
192 tdate_parse( char* str )
193 {
194 struct tm tm;
195 char* cp;
196 char str_mon[500], str_wday[500];
197 int tm_sec, tm_min, tm_hour, tm_mday, tm_year;
198 long tm_mon, tm_wday;
199 time_t t;
200
201 /* Initialize. */
202 memset( (char*) &tm, 0, sizeof(struct tm) );
203
204 /* Skip initial whitespace ourselves - sscanf is clumsy at this. */
205 for ( cp = str; *cp == ' ' || *cp == '\t'; ++cp )
206 continue;
207
208 /* And do the sscanfs. WARNING: you can add more formats here,
209 ** but be careful! You can easily screw up the parsing of existing
210 ** formats when you add new ones. The order is important.
211 */
212
213 /* DD-mth-YY HH:MM:SS GMT */
214 if ( sscanf( cp, "%d-%400[a-zA-Z]-%d %d:%d:%d GMT",
215 &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
216 &tm_sec ) == 6 &&
217 scan_mon( str_mon, &tm_mon ) )
218 {
219 tm.tm_mday = tm_mday;
220 tm.tm_mon = tm_mon;
221 tm.tm_year = tm_year;
222 tm.tm_hour = tm_hour;
223 tm.tm_min = tm_min;
224 tm.tm_sec = tm_sec;
225 }
226
227 /* DD mth YY HH:MM:SS GMT */
228 else if ( sscanf( cp, "%d %400[a-zA-Z] %d %d:%d:%d GMT",
229 &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
230 &tm_sec) == 6 &&
231 scan_mon( str_mon, &tm_mon ) )
232 {
233 tm.tm_mday = tm_mday;
234 tm.tm_mon = tm_mon;
235 tm.tm_year = tm_year;
236 tm.tm_hour = tm_hour;
237 tm.tm_min = tm_min;
238 tm.tm_sec = tm_sec;
239 }
240
241 /* HH:MM:SS GMT DD-mth-YY */
242 else if ( sscanf( cp, "%d:%d:%d GMT %d-%400[a-zA-Z]-%d",
243 &tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon,
244 &tm_year ) == 6 &&
245 scan_mon( str_mon, &tm_mon ) )
246 {
247 tm.tm_hour = tm_hour;
248 tm.tm_min = tm_min;
249 tm.tm_sec = tm_sec;
250 tm.tm_mday = tm_mday;
251 tm.tm_mon = tm_mon;
252 tm.tm_year = tm_year;
253 }
254
255 /* HH:MM:SS GMT DD mth YY */
256 else if ( sscanf( cp, "%d:%d:%d GMT %d %400[a-zA-Z] %d",
257 &tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon,
258 &tm_year ) == 6 &&
259 scan_mon( str_mon, &tm_mon ) )
260 {
261 tm.tm_hour = tm_hour;
262 tm.tm_min = tm_min;
263 tm.tm_sec = tm_sec;
264 tm.tm_mday = tm_mday;
265 tm.tm_mon = tm_mon;
266 tm.tm_year = tm_year;
267 }
268
269 /* wdy, DD-mth-YY HH:MM:SS GMT */
270 else if ( sscanf( cp, "%400[a-zA-Z], %d-%400[a-zA-Z]-%d %d:%d:%d GMT",
271 str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
272 &tm_sec ) == 7 &&
273 scan_wday( str_wday, &tm_wday ) &&
274 scan_mon( str_mon, &tm_mon ) )
275 {
276 tm.tm_wday = tm_wday;
277 tm.tm_mday = tm_mday;
278 tm.tm_mon = tm_mon;
279 tm.tm_year = tm_year;
280 tm.tm_hour = tm_hour;
281 tm.tm_min = tm_min;
282 tm.tm_sec = tm_sec;
283 }
284
285 /* wdy, DD mth YY HH:MM:SS GMT */
286 else if ( sscanf( cp, "%400[a-zA-Z], %d %400[a-zA-Z] %d %d:%d:%d GMT",
287 str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
288 &tm_sec ) == 7 &&
289 scan_wday( str_wday, &tm_wday ) &&
290 scan_mon( str_mon, &tm_mon ) )
291 {
292 tm.tm_wday = tm_wday;
293 tm.tm_mday = tm_mday;
294 tm.tm_mon = tm_mon;
295 tm.tm_year = tm_year;
296 tm.tm_hour = tm_hour;
297 tm.tm_min = tm_min;
298 tm.tm_sec = tm_sec;
299 }
300
301 /* wdy mth DD HH:MM:SS GMT YY */
302 else if ( sscanf( cp, "%400[a-zA-Z] %400[a-zA-Z] %d %d:%d:%d GMT %d",
303 str_wday, str_mon, &tm_mday, &tm_hour, &tm_min, &tm_sec,
304 &tm_year ) == 7 &&
305 scan_wday( str_wday, &tm_wday ) &&
306 scan_mon( str_mon, &tm_mon ) )
307 {
308 tm.tm_wday = tm_wday;
309 tm.tm_mon = tm_mon;
310 tm.tm_mday = tm_mday;
311 tm.tm_hour = tm_hour;
312 tm.tm_min = tm_min;
313 tm.tm_sec = tm_sec;
314 tm.tm_year = tm_year;
315 }
316 else
317 return (time_t) -1;
318
319 if ( tm.tm_year > 1900 )
320 tm.tm_year -= 1900;
321 else if ( tm.tm_year < 70 )
322 tm.tm_year += 100;
323
324 t = tm_to_time( &tm );
325
326 return t;
327 }