2 ** Copyright 1998 - 2011 Double Precision, Inc.
3 ** See COPYING for distribution information.
13 #define my_isalpha(c) ( ( (c) >= 'a' && (c) <= 'z' ) || \
14 ( (c) >= 'A' && (c) <= 'Z' ) )
16 #define my_isdigit(c) ( (c) >= '0' && (c) <= '9' )
18 #define my_isalnum(c) ( my_isalpha(c) || my_isdigit(c) )
20 #define my_isspace(c) ( (c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n')
23 ** time_t rfc822_parsedate(const char *p)
25 ** p - contents of the Date: header, attempt to parse it into a time_t.
27 ** returns - time_t, or 0 if the date cannot be parsed
30 static unsigned parsedig(const char **p
)
34 while (my_isdigit(**p
))
42 static const char * const weekdays
[7]={
43 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
46 static const char * const mnames
[13]={
47 "Jan", "Feb", "Mar", "Apr",
48 "May", "Jun", "Jul", "Aug",
49 "Sep", "Oct", "Nov", "Dec", NULL
};
53 (((y) % 4) == 0 && (y) % 100) )
55 static unsigned mlength
[]={31,28,31,30,31,30,31,31,30,31,30,31};
56 #define mdays(m,y) ( (m) != 2 ? mlength[(m)-1] : leap(y) ? 29:28)
58 static const char * const zonenames
[] = {
65 "A", "B", "C", "D", "E", "F", "G", "H", "I", "K", "L", "M",
66 "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y",
69 #define ZH(n) ( (n) * 60 * 60 )
71 static int zoneoffset
[] = {
79 ZH(-1), ZH(-2), ZH(-3), ZH(-4), ZH(-5), ZH(-6), ZH(-7), ZH(-8), ZH(-9), ZH(-10), ZH(-11), ZH(-12),
80 ZH(1), ZH(2), ZH(3), ZH(4), ZH(5), ZH(6), ZH(7), ZH(8), ZH(9), ZH(10), ZH(11), ZH(12) };
82 #define lc(x) ((x) >= 'A' && (x) <= 'Z' ? (x) + ('a'-'A'):(x))
84 static unsigned parsekey(const char **mon
, const char * const *ary
)
88 for (m
=0; ary
[m
]; m
++)
90 for (j
=0; ary
[m
][j
]; j
++)
91 if (lc(ary
[m
][j
]) != lc((*mon
)[j
]))
102 static int parsetime(const char **t
)
106 if (!my_isdigit(**t
)) return (-1);
109 if (h
> 23) return (-1);
110 if (**t
!= ':') return (-1);
112 if (!my_isdigit(**t
)) return (-1);
118 if (!my_isdigit(**t
)) return (-1);
121 if (m
> 59 || s
> 59) return (-1);
122 return (h
* 60 * 60 + m
* 60 + s
);
125 time_t rfc822_parsedt(const char *rfcdt
)
127 unsigned day
=0, mon
=0, year
;
133 /* Ignore day of the week. Tolerate "Tue, 25 Feb 1997 ... "
134 ** without the comma. Tolerate "Feb 25 1997 ...".
139 if (!*rfcdt
) return (0);
140 if (my_isalpha(*rfcdt
))
143 mon
=parsekey(&rfcdt
, mnames
);
145 while (*rfcdt
&& my_isalpha(*rfcdt
))
150 if (my_isdigit(*rfcdt
))
153 day
=parsedig(&rfcdt
);
154 if (!day
) return (0);
160 while (*rfcdt
&& my_isspace(*rfcdt
))
162 if (!my_isdigit(*rfcdt
)) return (0);
163 year
=parsedig(&rfcdt
);
164 if (year
< 70) year
+= 2000;
165 if (year
< 100) year
+= 1900;
167 while (*rfcdt
&& my_isspace(*rfcdt
))
170 if (day
== 0 || mon
== 0 || mon
> 12 || day
> mdays(mon
,year
))
173 secs
=parsetime(&rfcdt
);
174 if (secs
< 0) return (0);
178 /* RFC822 sez no parenthesis, but I've seen (EST) */
182 if (my_isalnum(*rfcdt
) || *rfcdt
== '+' || *rfcdt
== '-')
187 if (my_isalpha((int)(unsigned char)*rfcdt
))
189 int n
=parsekey(&rfcdt
, zonenames
);
191 if (n
> 0) offset
= zoneoffset
[n
-1];
205 if (my_isdigit(*rfcdt
))
208 if (n
> 2359 || (n
% 100) > 59) n
=0;
209 offset
= sign
* ( (n
% 100) * 60 + n
/ 100 * 60 * 60);
213 if (year
< 1970) return (0);
214 if (year
> 9999) return (0);
217 for (y
=1970; y
<year
; y
++)
224 t
+= ( 365*3+366 ) * 24 * 60 * 60;
229 t
+= 365 * 24 * 60 * 60;
232 for (y
=1; y
< mon
; y
++)
233 t
+= mdays(y
, year
) * 24 * 60 * 60;
235 return ( t
+ (day
-1) * 24 * 60 * 60 + secs
- offset
);
238 const char *rfc822_mkdt(time_t t
)
241 struct tm
*tmptr
=gmtime(&t
);
246 sprintf(buf
, "%s, %02d %s %04d %02d:%02d:%02d GMT",
247 weekdays
[tmptr
->tm_wday
],
249 mnames
[tmptr
->tm_mon
],
250 tmptr
->tm_year
+ 1900,