2 ** Copyright 1998 - 1999 Double Precision, Inc.
3 ** See COPYING for distribution information.
7 ** $Id: rfc822_parsedt.c,v 1.4 2002/05/21 16:02:19 mrsam Exp $
15 ** time_t rfc822_parsedate(const char *p)
17 ** p - contents of the Date: header, attempt to parse it into a time_t.
19 ** returns - time_t, or 0 if the date cannot be parsed
22 static unsigned parsedig(const char **p
)
26 while (isdigit((int)(unsigned char)**p
))
34 static const char * const weekdays
[7]={
35 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
38 static const char * const mnames
[13]={
39 "Jan", "Feb", "Mar", "Apr",
40 "May", "Jun", "Jul", "Aug",
41 "Sep", "Oct", "Nov", "Dec", NULL
};
45 (((y) % 4) == 0 && (y) % 100) )
47 static unsigned mlength
[]={31,28,31,30,31,30,31,31,30,31,30,31};
48 #define mdays(m,y) ( (m) != 2 ? mlength[(m)-1] : leap(y) ? 29:28)
50 static const char * const zonenames
[] = {
57 "A", "B", "C", "D", "E", "F", "G", "H", "I", "K", "L", "M",
58 "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y",
61 #define ZH(n) ( (n) * 60 * 60 )
63 static int zoneoffset
[] = {
71 ZH(-1), ZH(-2), ZH(-3), ZH(-4), ZH(-5), ZH(-6), ZH(-7), ZH(-8), ZH(-9), ZH(-10), ZH(-11), ZH(-12),
72 ZH(1), ZH(2), ZH(3), ZH(4), ZH(5), ZH(6), ZH(7), ZH(8), ZH(9), ZH(10), ZH(11), ZH(12) };
74 static unsigned parsekey(const char **mon
, const char * const *ary
)
78 for (m
=0; ary
[m
]; m
++)
80 for (j
=0; ary
[m
][j
]; j
++)
81 if (tolower(ary
[m
][j
]) != tolower((*mon
)[j
]))
92 static int parsetime(const char **t
)
96 if (!isdigit((int)(unsigned char)**t
)) return (-1);
98 if (h
> 23) return (-1);
99 if (**t
!= ':') return (-1);
101 if (!isdigit((int)(unsigned char)**t
)) return (-1);
106 if (!isdigit((int)(unsigned char)**t
)) return (-1);
109 if (m
> 59 || s
> 59) return (-1);
110 return (h
* 60 * 60 + m
* 60 + s
);
113 time_t rfc822_parsedt(const char *rfcdt
)
115 unsigned day
=0, mon
=0, year
;
121 /* Ignore day of the week. Tolerate "Tue, 25 Feb 1997 ... "
122 ** without the comma. Tolerate "Feb 25 1997 ...".
127 if (!*rfcdt
) return (0);
128 if (isalpha((int)(unsigned char)*rfcdt
))
131 mon
=parsekey(&rfcdt
, mnames
);
133 while (*rfcdt
&& isalpha((int)(unsigned char)*rfcdt
))
138 if (isdigit((int)(unsigned char)*rfcdt
))
141 day
=parsedig(&rfcdt
);
142 if (!day
) return (0);
148 while (*rfcdt
&& isspace((int)(unsigned char)*rfcdt
))
150 if (!isdigit((int)(unsigned char)*rfcdt
)) return (0);
151 year
=parsedig(&rfcdt
);
152 if (year
< 70) year
+= 2000;
153 if (year
< 100) year
+= 1900;
155 while (*rfcdt
&& isspace((int)(unsigned char)*rfcdt
))
158 if (day
== 0 || mon
== 0 || mon
> 12 || day
> mdays(mon
,year
))
161 secs
=parsetime(&rfcdt
);
162 if (secs
< 0) return (0);
166 /* RFC822 sez no parenthesis, but I've seen (EST) */
170 if (isalnum((int)(unsigned char)*rfcdt
) || *rfcdt
== '+' || *rfcdt
== '-')
175 if (isalpha((int)(unsigned char)*rfcdt
))
177 int n
=parsekey(&rfcdt
, zonenames
);
179 if (n
> 0) offset
= zoneoffset
[n
-1];
193 if (isdigit((int)(unsigned char)*rfcdt
))
196 if (n
> 2359 || (n
% 100) > 59) n
=0;
197 offset
= sign
* ( (n
% 100) * 60 + n
/ 100 * 60 * 60);
201 if (year
< 1970) return (0);
202 if (year
> 9999) return (0);
205 for (y
=1970; y
<year
; y
++)
212 t
+= ( 365*3+366 ) * 24 * 60 * 60;
217 t
+= 365 * 24 * 60 * 60;
220 for (y
=1; y
< mon
; y
++)
221 t
+= mdays(y
, year
) * 24 * 60 * 60;
223 return ( t
+ (day
-1) * 24 * 60 * 60 + secs
- offset
);
226 const char *rfc822_mkdt(time_t t
)
229 struct tm
*tmptr
=gmtime(&t
);
234 sprintf(buf
, "%s, %02d %s %04d %02d:%02d:%02d GMT",
235 weekdays
[tmptr
->tm_wday
],
237 mnames
[tmptr
->tm_mon
],
238 tmptr
->tm_year
+ 1900,