xref: /plan9/sys/src/libhttpd/date.c (revision 6b6b9ac8b0b103b1e30e4d019522a78c950fce74)
180ee5cbfSDavid du Colombier #include <u.h>
280ee5cbfSDavid du Colombier #include <libc.h>
380ee5cbfSDavid du Colombier #include <httpd.h>
480ee5cbfSDavid du Colombier 
580ee5cbfSDavid du Colombier /*
680ee5cbfSDavid du Colombier  * print dates in the format
780ee5cbfSDavid du Colombier  * Wkd, DD Mon YYYY HH:MM:SS GMT
880ee5cbfSDavid du Colombier  * parse dates of formats
980ee5cbfSDavid du Colombier  * Wkd, DD Mon YYYY HH:MM:SS GMT
1080ee5cbfSDavid du Colombier  * Weekday, DD-Mon-YY HH:MM:SS GMT
1180ee5cbfSDavid du Colombier  * Wkd Mon ( D|DD) HH:MM:SS YYYY
1280ee5cbfSDavid du Colombier  * plus anything similar
1380ee5cbfSDavid du Colombier  */
1480ee5cbfSDavid du Colombier static char *
1580ee5cbfSDavid du Colombier weekdayname[7] =
1680ee5cbfSDavid du Colombier {
1780ee5cbfSDavid du Colombier 	"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
1880ee5cbfSDavid du Colombier };
1980ee5cbfSDavid du Colombier static char *
2080ee5cbfSDavid du Colombier wdayname[7] =
2180ee5cbfSDavid du Colombier {
2280ee5cbfSDavid du Colombier 	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
2380ee5cbfSDavid du Colombier };
2480ee5cbfSDavid du Colombier 
2580ee5cbfSDavid du Colombier static char *
2680ee5cbfSDavid du Colombier monname[12] =
2780ee5cbfSDavid du Colombier {
2880ee5cbfSDavid du Colombier 	"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
2980ee5cbfSDavid du Colombier };
3080ee5cbfSDavid du Colombier 
3180ee5cbfSDavid du Colombier static	int	dateindex(char*, char**, int);
3280ee5cbfSDavid du Colombier 
3380ee5cbfSDavid du Colombier static int
dtolower(int c)3480ee5cbfSDavid du Colombier dtolower(int c)
3580ee5cbfSDavid du Colombier {
3680ee5cbfSDavid du Colombier 	if(c >= 'A' && c <= 'Z')
3780ee5cbfSDavid du Colombier 		return c - 'A' + 'a';
3880ee5cbfSDavid du Colombier 	return c;
3980ee5cbfSDavid du Colombier }
4080ee5cbfSDavid du Colombier 
4180ee5cbfSDavid du Colombier static int
disalpha(int c)4280ee5cbfSDavid du Colombier disalpha(int c)
4380ee5cbfSDavid du Colombier {
4480ee5cbfSDavid du Colombier 	return c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z';
4580ee5cbfSDavid du Colombier }
4680ee5cbfSDavid du Colombier 
4780ee5cbfSDavid du Colombier static int
disdig(int c)4880ee5cbfSDavid du Colombier disdig(int c)
4980ee5cbfSDavid du Colombier {
5080ee5cbfSDavid du Colombier 	return c >= '0' && c <= '9';
5180ee5cbfSDavid du Colombier }
5280ee5cbfSDavid du Colombier 
5380ee5cbfSDavid du Colombier int
hdatefmt(Fmt * f)549a747e4fSDavid du Colombier hdatefmt(Fmt *f)
5580ee5cbfSDavid du Colombier {
5680ee5cbfSDavid du Colombier 	Tm *tm;
5780ee5cbfSDavid du Colombier 	ulong t;
5880ee5cbfSDavid du Colombier 
599a747e4fSDavid du Colombier 	t = va_arg(f->args, ulong);
6080ee5cbfSDavid du Colombier 	tm = gmtime(t);
619a747e4fSDavid du Colombier 	return fmtprint(f, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
6280ee5cbfSDavid du Colombier 		wdayname[tm->wday], tm->mday, monname[tm->mon], tm->year+1900,
6380ee5cbfSDavid du Colombier 		tm->hour, tm->min, tm->sec);
6480ee5cbfSDavid du Colombier }
6580ee5cbfSDavid du Colombier 
6680ee5cbfSDavid du Colombier static char*
dateword(char * date,char * buf)6780ee5cbfSDavid du Colombier dateword(char *date, char *buf)
6880ee5cbfSDavid du Colombier {
6980ee5cbfSDavid du Colombier 	char *p;
7080ee5cbfSDavid du Colombier 	int c;
7180ee5cbfSDavid du Colombier 
7280ee5cbfSDavid du Colombier 	p = buf;
7380ee5cbfSDavid du Colombier 	while(!disalpha(c = *date) && !disdig(c) && c)
7480ee5cbfSDavid du Colombier 		date++;
7580ee5cbfSDavid du Colombier 	while(disalpha(c = *date)){
7680ee5cbfSDavid du Colombier 		if(p - buf < 30)
7780ee5cbfSDavid du Colombier 			*p++ = dtolower(c);
7880ee5cbfSDavid du Colombier 		date++;
7980ee5cbfSDavid du Colombier 	}
8080ee5cbfSDavid du Colombier 	*p = 0;
8180ee5cbfSDavid du Colombier 	return date;
8280ee5cbfSDavid du Colombier }
8380ee5cbfSDavid du Colombier 
8480ee5cbfSDavid du Colombier static int
datenum(char ** d)8580ee5cbfSDavid du Colombier datenum(char **d)
8680ee5cbfSDavid du Colombier {
8780ee5cbfSDavid du Colombier 	char *date;
8880ee5cbfSDavid du Colombier 	int c, n;
8980ee5cbfSDavid du Colombier 
9080ee5cbfSDavid du Colombier 	date = *d;
9180ee5cbfSDavid du Colombier 	while(!disdig(c = *date) && c)
9280ee5cbfSDavid du Colombier 		date++;
9380ee5cbfSDavid du Colombier 	if(c == 0){
9480ee5cbfSDavid du Colombier 		*d = date;
9580ee5cbfSDavid du Colombier 		return -1;
9680ee5cbfSDavid du Colombier 	}
9780ee5cbfSDavid du Colombier 	n = 0;
9880ee5cbfSDavid du Colombier 	while(disdig(c = *date)){
9980ee5cbfSDavid du Colombier 		n = n * 10 + c - '0';
10080ee5cbfSDavid du Colombier 		date++;
10180ee5cbfSDavid du Colombier 	}
10280ee5cbfSDavid du Colombier 	*d = date;
10380ee5cbfSDavid du Colombier 	return n;
10480ee5cbfSDavid du Colombier }
10580ee5cbfSDavid du Colombier 
10680ee5cbfSDavid du Colombier /*
10780ee5cbfSDavid du Colombier  * parse a date and return the seconds since the epoch
10880ee5cbfSDavid du Colombier  * return 0 for a failure
10980ee5cbfSDavid du Colombier  */
11080ee5cbfSDavid du Colombier ulong
hdate2sec(char * date)11180ee5cbfSDavid du Colombier hdate2sec(char *date)
11280ee5cbfSDavid du Colombier {
11380ee5cbfSDavid du Colombier 	Tm tm;
11480ee5cbfSDavid du Colombier 	char buf[32];
11580ee5cbfSDavid du Colombier 
11680ee5cbfSDavid du Colombier 	/*
11780ee5cbfSDavid du Colombier 	 * Weekday|Wday
11880ee5cbfSDavid du Colombier 	 */
11980ee5cbfSDavid du Colombier 	date = dateword(date, buf);
12080ee5cbfSDavid du Colombier 	tm.wday = dateindex(buf, wdayname, 7);
12180ee5cbfSDavid du Colombier 	if(tm.wday < 0)
12280ee5cbfSDavid du Colombier 		tm.wday = dateindex(buf, weekdayname, 7);
12380ee5cbfSDavid du Colombier 	if(tm.wday < 0)
12480ee5cbfSDavid du Colombier 		return 0;
12580ee5cbfSDavid du Colombier 
12680ee5cbfSDavid du Colombier 	/*
12780ee5cbfSDavid du Colombier 	 * check for the two major formats
12880ee5cbfSDavid du Colombier 	 */
12980ee5cbfSDavid du Colombier 	date = dateword(date, buf);
13080ee5cbfSDavid du Colombier 	tm.mon = dateindex(buf, monname, 12);
13180ee5cbfSDavid du Colombier 	if(tm.mon >= 0){
13280ee5cbfSDavid du Colombier 		/*
13380ee5cbfSDavid du Colombier 		 * MM
13480ee5cbfSDavid du Colombier 		 */
13580ee5cbfSDavid du Colombier 		tm.mday = datenum(&date);
13680ee5cbfSDavid du Colombier 		if(tm.mday < 1 || tm.mday > 31)
13780ee5cbfSDavid du Colombier 			return 0;
13880ee5cbfSDavid du Colombier 
13980ee5cbfSDavid du Colombier 		/*
14080ee5cbfSDavid du Colombier 		 * HH:MM:SS
14180ee5cbfSDavid du Colombier 		 */
14280ee5cbfSDavid du Colombier 		tm.hour = datenum(&date);
14380ee5cbfSDavid du Colombier 		if(tm.hour < 0 || tm.hour >= 24)
14480ee5cbfSDavid du Colombier 			return 0;
14580ee5cbfSDavid du Colombier 		tm.min = datenum(&date);
14680ee5cbfSDavid du Colombier 		if(tm.min < 0 || tm.min >= 60)
14780ee5cbfSDavid du Colombier 			return 0;
14880ee5cbfSDavid du Colombier 		tm.sec = datenum(&date);
14980ee5cbfSDavid du Colombier 		if(tm.sec < 0 || tm.sec >= 60)
15080ee5cbfSDavid du Colombier 			return 0;
15180ee5cbfSDavid du Colombier 
15280ee5cbfSDavid du Colombier 		/*
15380ee5cbfSDavid du Colombier 		 * YYYY
15480ee5cbfSDavid du Colombier 		 */
15580ee5cbfSDavid du Colombier 		tm.year = datenum(&date);
15680ee5cbfSDavid du Colombier 		if(tm.year < 70 || tm.year > 99 && tm.year < 1970)
15780ee5cbfSDavid du Colombier 			return 0;
15880ee5cbfSDavid du Colombier 		if(tm.year >= 1970)
15980ee5cbfSDavid du Colombier 			tm.year -= 1900;
16080ee5cbfSDavid du Colombier 	}else{
16180ee5cbfSDavid du Colombier 		/*
16280ee5cbfSDavid du Colombier 		 * MM-Mon-(YY|YYYY)
16380ee5cbfSDavid du Colombier 		 */
16480ee5cbfSDavid du Colombier 		tm.mday = datenum(&date);
16580ee5cbfSDavid du Colombier 		if(tm.mday < 1 || tm.mday > 31)
16680ee5cbfSDavid du Colombier 			return 0;
16780ee5cbfSDavid du Colombier 		date = dateword(date, buf);
16880ee5cbfSDavid du Colombier 		tm.mon = dateindex(buf, monname, 12);
16980ee5cbfSDavid du Colombier 		if(tm.mon < 0 || tm.mon >= 12)
17080ee5cbfSDavid du Colombier 			return 0;
17180ee5cbfSDavid du Colombier 		tm.year = datenum(&date);
17280ee5cbfSDavid du Colombier 		if(tm.year < 70 || tm.year > 99 && tm.year < 1970)
17380ee5cbfSDavid du Colombier 			return 0;
17480ee5cbfSDavid du Colombier 		if(tm.year >= 1970)
17580ee5cbfSDavid du Colombier 			tm.year -= 1900;
17680ee5cbfSDavid du Colombier 
17780ee5cbfSDavid du Colombier 		/*
17880ee5cbfSDavid du Colombier 		 * HH:MM:SS
17980ee5cbfSDavid du Colombier 		 */
18080ee5cbfSDavid du Colombier 		tm.hour = datenum(&date);
18180ee5cbfSDavid du Colombier 		if(tm.hour < 0 || tm.hour >= 24)
18280ee5cbfSDavid du Colombier 			return 0;
18380ee5cbfSDavid du Colombier 		tm.min = datenum(&date);
18480ee5cbfSDavid du Colombier 		if(tm.min < 0 || tm.min >= 60)
18580ee5cbfSDavid du Colombier 			return 0;
18680ee5cbfSDavid du Colombier 		tm.sec = datenum(&date);
18780ee5cbfSDavid du Colombier 		if(tm.sec < 0 || tm.sec >= 60)
18880ee5cbfSDavid du Colombier 			return 0;
18980ee5cbfSDavid du Colombier 
19080ee5cbfSDavid du Colombier 		/*
19180ee5cbfSDavid du Colombier 		 * timezone
19280ee5cbfSDavid du Colombier 		 */
19380ee5cbfSDavid du Colombier 		dateword(date, buf);
19480ee5cbfSDavid du Colombier 		if(strncmp(buf, "gmt", 3) != 0)
19580ee5cbfSDavid du Colombier 			return 0;
19680ee5cbfSDavid du Colombier 	}
19780ee5cbfSDavid du Colombier 
19880ee5cbfSDavid du Colombier 	strcpy(tm.zone, "GMT");
19980ee5cbfSDavid du Colombier 	tm.tzoff = 0;
200*6b6b9ac8SDavid du Colombier 	tm.yday = 0;
20180ee5cbfSDavid du Colombier 	return tm2sec(&tm);
20280ee5cbfSDavid du Colombier }
20380ee5cbfSDavid du Colombier 
20480ee5cbfSDavid du Colombier static int
dateindex(char * d,char ** tab,int n)20580ee5cbfSDavid du Colombier dateindex(char *d, char **tab, int n)
20680ee5cbfSDavid du Colombier {
20780ee5cbfSDavid du Colombier 	int i;
20880ee5cbfSDavid du Colombier 
20980ee5cbfSDavid du Colombier 	for(i = 0; i < n; i++)
21080ee5cbfSDavid du Colombier 		if(cistrcmp(d, tab[i]) == 0)
21180ee5cbfSDavid du Colombier 			return i;
21280ee5cbfSDavid du Colombier 	return -1;
21380ee5cbfSDavid du Colombier }
214