188 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			188 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/**
 | 
						|
 * @PROJECT			Kagera uHTTP Daemon
 | 
						|
 * @COPYRIGHT		See COPYING in the top level directory
 | 
						|
 * @FILE			dateparse.c
 | 
						|
 * @PURPOSE			Parses string dates into internal form
 | 
						|
 * @DEVELOPERS		Rafal Kupiec <belliash@asiotec.eu.org>
 | 
						|
 *					Jef Poskanzer <jef@acme.com>
 | 
						|
 */
 | 
						|
 | 
						|
#include <sys/types.h>
 | 
						|
#include <ctype.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <string.h>
 | 
						|
#include <time.h>
 | 
						|
 | 
						|
#include "dateparse.h"
 | 
						|
 | 
						|
time_t dateparse(char* str) {
 | 
						|
	struct tm tm;
 | 
						|
	char* cp;
 | 
						|
	char str_mon[500], str_wday[500];
 | 
						|
	int tm_sec, tm_min, tm_hour, tm_mday, tm_year;
 | 
						|
	long tm_mon, tm_wday;
 | 
						|
 | 
						|
	(void) memset((char*) &tm, 0, sizeof(struct tm));
 | 
						|
	for(cp = str; *cp == ' ' || *cp == '\t'; ++cp) {
 | 
						|
		continue;
 | 
						|
	}
 | 
						|
	if(sscanf(cp, "%d-%400[a-zA-Z]-%d %d:%d:%d GMT", &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min, &tm_sec) == 6 && scan_mon(str_mon, &tm_mon)) {
 | 
						|
		tm.tm_mday = tm_mday;
 | 
						|
		tm.tm_mon = tm_mon;
 | 
						|
		tm.tm_year = tm_year;
 | 
						|
		tm.tm_hour = tm_hour;
 | 
						|
		tm.tm_min = tm_min;
 | 
						|
		tm.tm_sec = tm_sec;
 | 
						|
	} else if(sscanf(cp, "%d %400[a-zA-Z] %d %d:%d:%d GMT", &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min, &tm_sec) == 6 && scan_mon(str_mon, &tm_mon)) {
 | 
						|
		tm.tm_mday = tm_mday;
 | 
						|
		tm.tm_mon = tm_mon;
 | 
						|
		tm.tm_year = tm_year;
 | 
						|
		tm.tm_hour = tm_hour;
 | 
						|
		tm.tm_min = tm_min;
 | 
						|
		tm.tm_sec = tm_sec;
 | 
						|
	} else if(sscanf(cp, "%d:%d:%d GMT %d-%400[a-zA-Z]-%d", &tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon, &tm_year) == 6 && scan_mon(str_mon, &tm_mon)) {
 | 
						|
		tm.tm_hour = tm_hour;
 | 
						|
		tm.tm_min = tm_min;
 | 
						|
		tm.tm_sec = tm_sec;
 | 
						|
		tm.tm_mday = tm_mday;
 | 
						|
		tm.tm_mon = tm_mon;
 | 
						|
		tm.tm_year = tm_year;
 | 
						|
	} else if(sscanf(cp, "%d:%d:%d GMT %d %400[a-zA-Z] %d", &tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon, &tm_year) == 6 && scan_mon(str_mon, &tm_mon)) {
 | 
						|
		tm.tm_hour = tm_hour;
 | 
						|
		tm.tm_min = tm_min;
 | 
						|
		tm.tm_sec = tm_sec;
 | 
						|
		tm.tm_mday = tm_mday;
 | 
						|
		tm.tm_mon = tm_mon;
 | 
						|
		tm.tm_year = tm_year;
 | 
						|
	} else if(sscanf(cp, "%400[a-zA-Z], %d-%400[a-zA-Z]-%d %d:%d:%d GMT", str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min, &tm_sec) == 7 && scan_wday(str_wday, &tm_wday) && scan_mon(str_mon, &tm_mon)) {
 | 
						|
		tm.tm_wday = tm_wday;
 | 
						|
		tm.tm_mday = tm_mday;
 | 
						|
		tm.tm_mon = tm_mon;
 | 
						|
		tm.tm_year = tm_year;
 | 
						|
		tm.tm_hour = tm_hour;
 | 
						|
		tm.tm_min = tm_min;
 | 
						|
		tm.tm_sec = tm_sec;
 | 
						|
	} else if(sscanf(cp, "%400[a-zA-Z], %d %400[a-zA-Z] %d %d:%d:%d GMT", str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min, &tm_sec) == 7 && scan_wday(str_wday, &tm_wday) && scan_mon(str_mon, &tm_mon)) {
 | 
						|
		tm.tm_wday = tm_wday;
 | 
						|
		tm.tm_mday = tm_mday;
 | 
						|
		tm.tm_mon = tm_mon;
 | 
						|
		tm.tm_year = tm_year;
 | 
						|
		tm.tm_hour = tm_hour;
 | 
						|
		tm.tm_min = tm_min;
 | 
						|
		tm.tm_sec = tm_sec;
 | 
						|
	} else if(sscanf(cp, "%400[a-zA-Z] %400[a-zA-Z] %d %d:%d:%d GMT %d", str_wday, str_mon, &tm_mday, &tm_hour, &tm_min, &tm_sec, &tm_year) == 7 && scan_wday(str_wday, &tm_wday) && scan_mon(str_mon, &tm_mon)) {
 | 
						|
		tm.tm_wday = tm_wday;
 | 
						|
		tm.tm_mon = tm_mon;
 | 
						|
		tm.tm_mday = tm_mday;
 | 
						|
		tm.tm_hour = tm_hour;
 | 
						|
		tm.tm_min = tm_min;
 | 
						|
		tm.tm_sec = tm_sec;
 | 
						|
		tm.tm_year = tm_year;
 | 
						|
	} else {
 | 
						|
		return (time_t) -1;
 | 
						|
	}
 | 
						|
	if(tm.tm_year > 1900) {
 | 
						|
		tm.tm_year -= 1900;
 | 
						|
	} else if(tm.tm_year < 70) {
 | 
						|
		tm.tm_year += 100;
 | 
						|
	}
 | 
						|
	return tm_to_time(&tm);
 | 
						|
}
 | 
						|
 | 
						|
static int is_leap(int year) {
 | 
						|
	return year % 400? (year % 100 ? (year % 4 ? 0 : 1) : 0) : 1;
 | 
						|
}
 | 
						|
 | 
						|
static void pound_case(char* str) {
 | 
						|
	for(; *str != '\0'; ++str) {
 | 
						|
		if(isupper((int) *str)) {
 | 
						|
			*str = tolower((int) *str);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int scan_mon(char* str_mon, long* tm_monP) {
 | 
						|
	static struct strlong mon_tab[] = {
 | 
						|
		{ "jan", 0 }, { "january", 0 },
 | 
						|
		{ "feb", 1 }, { "february", 1 },
 | 
						|
		{ "mar", 2 }, { "march", 2 },
 | 
						|
		{ "apr", 3 }, { "april", 3 },
 | 
						|
		{ "may", 4 },
 | 
						|
		{ "jun", 5 }, { "june", 5 },
 | 
						|
		{ "jul", 6 }, { "july", 6 },
 | 
						|
		{ "aug", 7 }, { "august", 7 },
 | 
						|
		{ "sep", 8 }, { "september", 8 },
 | 
						|
		{ "oct", 9 }, { "october", 9 },
 | 
						|
		{ "nov", 10 }, { "november", 10 },
 | 
						|
		{ "dec", 11 }, { "december", 11 },
 | 
						|
	};
 | 
						|
	static int sorted = 0;
 | 
						|
	if(!sorted) {
 | 
						|
		(void) qsort(mon_tab, sizeof(mon_tab) / sizeof(struct strlong), sizeof(struct strlong), (int(*)(const void*, const void*)) strlong_compare);
 | 
						|
		sorted = 1;
 | 
						|
	}
 | 
						|
	pound_case(str_mon);
 | 
						|
	return strlong_search(str_mon, mon_tab, sizeof(mon_tab) / sizeof(struct strlong), tm_monP);
 | 
						|
}
 | 
						|
 | 
						|
static int scan_wday(char* str_wday, long* tm_wdayP) {
 | 
						|
	static struct strlong wday_tab[] = {
 | 
						|
		{ "sun", 0 }, { "sunday", 0 },
 | 
						|
		{ "mon", 1 }, { "monday", 1 },
 | 
						|
		{ "tue", 2 }, { "tuesday", 2 },
 | 
						|
		{ "wed", 3 }, { "wednesday", 3 },
 | 
						|
		{ "thu", 4 }, { "thursday", 4 },
 | 
						|
		{ "fri", 5 }, { "friday", 5 },
 | 
						|
		{ "sat", 6 }, { "saturday", 6 },
 | 
						|
	};
 | 
						|
	static int sorted = 0;
 | 
						|
	if(!sorted) {
 | 
						|
		(void) qsort(wday_tab, sizeof(wday_tab) / sizeof(struct strlong), sizeof(struct strlong), (int(*)(const void*, const void*)) strlong_compare);
 | 
						|
		sorted = 1;
 | 
						|
	}
 | 
						|
	pound_case(str_wday);
 | 
						|
	return strlong_search(str_wday, wday_tab, sizeof(wday_tab) / sizeof(struct strlong), tm_wdayP);
 | 
						|
}
 | 
						|
 | 
						|
static int strlong_compare(char *v1, char *v2) {
 | 
						|
	return strcmp(((struct strlong*) v1)->s, ((struct strlong*) v2)->s);
 | 
						|
}
 | 
						|
 | 
						|
static int strlong_search(char* str, struct strlong* tab, int n, long* lP) {
 | 
						|
	int i, h, l, r;
 | 
						|
	l = 0;
 | 
						|
	h = n - 1;
 | 
						|
	for(;;) {
 | 
						|
		i = (h + l) / 2;
 | 
						|
		r = strcmp(str, tab[i].s);
 | 
						|
		if(r < 0) {
 | 
						|
			h = i - 1;
 | 
						|
		} else if(r > 0) {
 | 
						|
			l = i + 1;
 | 
						|
		} else {
 | 
						|
			*lP = tab[i].l;
 | 
						|
			return 1;
 | 
						|
		}
 | 
						|
		if(h < l) {
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static time_t tm_to_time(struct tm* tmP) {
 | 
						|
	time_t t;
 | 
						|
	static int monthtab[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
 | 
						|
	t = (tmP->tm_year - 70) * 365;
 | 
						|
	t += (tmP->tm_year - 69) / 4;
 | 
						|
	t += monthtab[tmP->tm_mon];
 | 
						|
	if(tmP->tm_mon >= 2 && is_leap(tmP->tm_year + 1900)) {
 | 
						|
		++t;
 | 
						|
	}
 | 
						|
	t += tmP->tm_mday - 1;
 | 
						|
	t = t * 24 + tmP->tm_hour;
 | 
						|
	t = t * 60 + tmP->tm_min;
 | 
						|
	t = t * 60 + tmP->tm_sec;
 | 
						|
	return t;
 | 
						|
}
 |