227 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			227 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * misc - data and miscellaneous routines
 | |
|  */
 | |
| /* $Header$ */
 | |
| 
 | |
| #include	<ctype.h>
 | |
| #include	<time.h>
 | |
| #include	<stdlib.h>
 | |
| #include	<string.h>
 | |
| 
 | |
| #include	"loc_time.h"
 | |
| 
 | |
| #define	RULE_LEN	120
 | |
| #define	TZ_LEN		10
 | |
| 
 | |
| /* Make sure that the strings do not end up in ROM.
 | |
|  * These strings probably contain the wrong value, and we cannot obtain the
 | |
|  * right value from the system. TZ is the only help.
 | |
|  */
 | |
| static char ntstr[TZ_LEN + 1] = "GMT";	/* string for normal time */
 | |
| static char dststr[TZ_LEN + 1] = "GDT";	/* string for daylight saving */
 | |
| 
 | |
| long	_timezone = 0;
 | |
| long	_dst_off = 60 * 60;
 | |
| int	_daylight = 0;
 | |
| 
 | |
| long	timezone = 0;
 | |
| int	daylight = 0;
 | |
| 
 | |
| 
 | |
| static struct dsttype {
 | |
| 	char ds_type;		/* Unknown, Julian, Zero-based or M */
 | |
| 	int ds_date[3];		/* months, weeks, days */
 | |
| 	long ds_sec;		/* usually 02:00:00 */
 | |
| }	dststart = { 'U', { 0, 0, 0 }, 2 * 60 * 60 }
 | |
| 	, dstend = { 'U', { 0, 0, 0 }, 2 * 60 * 60 };
 | |
| 
 | |
| const char *_days[] = {
 | |
| 			"Sunday", "Monday", "Tuesday", "Wednesday",
 | |
| 			"Thursday", "Friday", "Saturday"
 | |
| 		};
 | |
| 
 | |
| const char *_months[] = {
 | |
| 			"January", "February", "March",
 | |
| 			"April", "May", "June",
 | |
| 			"July", "August", "September",
 | |
| 			"October", "November", "December"
 | |
| 		};
 | |
| 
 | |
| const int _ytab[2][12] = {
 | |
| 		{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
 | |
| 		{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
 | |
| 	};
 | |
| 
 | |
| static const char *
 | |
| parseZoneName(register char *buf, register const char *p)
 | |
| {
 | |
| 	register int n = 0;
 | |
| 
 | |
| 	if (*p == ':') return NULL;
 | |
| 	while (*p && !isdigit(*p) && *p != ',' && *p != '-' && *p != '+') {
 | |
| 		if (n < TZ_LEN)
 | |
| 			*buf++ = *p;
 | |
| 		p++;
 | |
| 		n++;
 | |
| 	}
 | |
| 	if (n < 3) return NULL;				/* error */
 | |
| 	*buf = '\0';
 | |
| 	return p;
 | |
| }
 | |
| 
 | |
| static const char *
 | |
| parseTime(register long *tm, const char *p, register struct dsttype *dst)
 | |
| {
 | |
| 	register int n = 0;
 | |
| 	register const char *q = p;
 | |
| 	char ds_type = (dst ? dst->ds_type : '\0');
 | |
| 
 | |
| 	if (dst) dst->ds_type = 'U';
 | |
| 
 | |
| 	*tm = 0;
 | |
| 	while(*p >= '0' && *p <= '9') {
 | |
| 		n = 10 * n + (*p++ - '0');
 | |
| 	}
 | |
| 	if (q == p) return NULL;	/* "The hour shall be required" */
 | |
| 	if (n < 0 || n >= 24)	return NULL;
 | |
| 	*tm = n * 60 * 60;
 | |
| 	if (*p == ':') {
 | |
| 		p++;
 | |
| 		n = 0;
 | |
| 		while(*p >= '0' && *p <= '9') {
 | |
| 			n = 10 * n + (*p++ - '0');
 | |
| 		}
 | |
| 		if (q == p) return NULL;	/* format error */
 | |
| 		if (n < 0 || n >= 60)	return NULL;
 | |
| 		*tm += n * 60;
 | |
| 		if (*p == ':') {
 | |
| 			p++;
 | |
| 			n = 0;
 | |
| 			while(*p >= '0' && *p <= '9') {
 | |
| 				n = 10 * n + (*p++ - '0');
 | |
| 			}
 | |
| 			if (q == p) return NULL;	/* format error */
 | |
| 			if (n < 0 || n >= 60)	return NULL;
 | |
| 			*tm += n;
 | |
| 		}
 | |
| 	}
 | |
| 	if (dst) {
 | |
| 		dst->ds_type = ds_type;
 | |
| 		dst->ds_sec = *tm;
 | |
| 	}
 | |
| 	return p;
 | |
| }
 | |
| 
 | |
| static const char *
 | |
| parseDate(register char *buf, register const char *p, struct dsttype *dstinfo)
 | |
| {
 | |
| 	register const char *q;
 | |
| 	register int n = 0;
 | |
| 	int cnt = 0;
 | |
| 	const int bnds[3][2] =	{	{ 1, 12 },
 | |
| 					{ 1, 5 },
 | |
| 					{ 0, 6}
 | |
| 				 };
 | |
| 	char ds_type;
 | |
| 
 | |
| 	if (*p != 'M') {
 | |
| 		if (*p == 'J') {
 | |
| 			*buf++ = *p++;
 | |
| 			ds_type = 'J';
 | |
| 		}
 | |
| 		else	ds_type = 'Z';
 | |
| 		q = p;
 | |
| 		while(*p >= '0' && *p <= '9') {
 | |
| 			n = 10 * n + (*p - '0');
 | |
| 			*buf++ = *p++;
 | |
| 		}
 | |
| 		if (q == p) return NULL;	/* format error */
 | |
| 		if (n < (ds_type == 'J') || n > 365) return NULL;
 | |
| 		dstinfo->ds_type = ds_type;
 | |
| 		dstinfo->ds_date[0] = n;
 | |
| 		return p;
 | |
| 	}
 | |
| 	ds_type = 'M';
 | |
| 	do {
 | |
| 		*buf++ = *p++;
 | |
| 		q = p;
 | |
| 		n = 0;
 | |
| 		while(*p >= '0' && *p <= '9') {
 | |
| 			n = 10 * n + (*p - '0');
 | |
| 			*buf++ = *p++;
 | |
| 		}
 | |
| 		if (q == p) return NULL;	/* format error */
 | |
| 		if (n < bnds[cnt][0] || n > bnds[cnt][1]) return NULL;
 | |
| 		dstinfo->ds_date[cnt] = n;
 | |
| 		cnt++;
 | |
| 	} while (cnt < 3 && *p == '.');
 | |
| 	if (cnt != 3) return NULL;
 | |
| 	*buf = '\0';
 | |
| 	dstinfo->ds_type = ds_type;
 | |
| 	return p;
 | |
| }
 | |
| 
 | |
| static const char *
 | |
| parseRule(register char *buf, register const char *p)
 | |
| {
 | |
| 	long time;
 | |
| 	register const char *q;
 | |
| 
 | |
| 	if (!(p = parseDate(buf, p, &dststart))) return NULL;
 | |
| 	buf += strlen(buf);
 | |
| 	if (*p == '/') {
 | |
| 		q = ++p;
 | |
| 		if (!(p = parseTime(&time, p, &dststart))) return NULL;
 | |
| 		while( p != q) *buf++ = *q++;
 | |
| 	}
 | |
| 	if (*p != ',') return NULL;
 | |
| 	p++;
 | |
| 	if (!(p = parseDate(buf, p, &dstend))) return NULL;
 | |
| 	buf += strlen(buf);
 | |
| 	if (*p == '/') {
 | |
| 		q = ++p;
 | |
| 		if (!(p = parseTime(&time, p, &dstend))) return NULL;
 | |
| 		while((*buf++ = *q++));
 | |
| 	}
 | |
| 	if (*p) return NULL;
 | |
| 	return p;
 | |
| }
 | |
| 
 | |
| static int
 | |
| last_sunday(register int day, const register struct tm *timep)
 | |
| {
 | |
| 	int first = FIRSTSUNDAY(timep);
 | |
| 
 | |
| 	if (day >= 58 && LEAPYEAR(YEAR0 + timep->tm_year)) day++;
 | |
| 	if (day < first) return first;
 | |
| 	return day - (day - first) % 7;
 | |
| }
 | |
| 
 | |
| static int
 | |
| date_of(const register struct dsttype *dst, const struct tm *timep)
 | |
| {
 | |
| 	int leap = LEAPYEAR(YEAR0 + timep->tm_year);
 | |
| 	int firstday, tmpday;
 | |
| 	register int day, month;
 | |
| 
 | |
| 	if (dst->ds_type != 'M') {
 | |
| 		return dst->ds_date[0] -
 | |
| 			    ((dst->ds_type == 'J')
 | |
| 				&& leap
 | |
| 				&& dst->ds_date[0] < 58);
 | |
| 	}
 | |
| 	day = 0;
 | |
| 	month = 1;
 | |
| 	while (month < dst->ds_date[0]) {
 | |
| 		day += _ytab[leap][month - 1];
 | |
| 		month++;
 | |
| 	}
 | |
| 	firstday = (day + FIRSTDAYOF(timep)) % 7;
 | |
| 	tmpday = day;
 | |
| 	day += (dst->ds_date[2] - firstday + 7) % 7
 | |
| 		+ 7 * (dst->ds_date[1] - 1);
 | |
| 	if (day >= tmpday + _ytab[leap][month-1]) day -= 7;
 | |
| 	return day;
 | |
| }
 | |
| 
 | 
