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 (23 years 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

# User Rev Content
1 root 1.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     }