1: /* tdate_parse - parse string dates into internal form, stripped-down version
2: **
3: ** Copyright © 1995 by Jef Poskanzer <jef@mail.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: (void) 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: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>