diff options
Diffstat (limited to 'src/time')
| -rw-r--r-- | src/time/__asctime.c | 27 | ||||
| -rw-r--r-- | src/time/__time.h | 9 | ||||
| -rw-r--r-- | src/time/__time_to_tm.c | 81 | ||||
| -rw-r--r-- | src/time/__tm_to_time.c | 33 | ||||
| -rw-r--r-- | src/time/asctime.c | 9 | ||||
| -rw-r--r-- | src/time/asctime_r.c | 8 | ||||
| -rw-r--r-- | src/time/clock.c | 9 | ||||
| -rw-r--r-- | src/time/clock_gettime.c | 7 | ||||
| -rw-r--r-- | src/time/ctime.c | 6 | ||||
| -rw-r--r-- | src/time/ctime_r.c | 8 | ||||
| -rw-r--r-- | src/time/difftime.c | 6 | ||||
| -rw-r--r-- | src/time/gettimeofday.c | 9 | ||||
| -rw-r--r-- | src/time/gmtime.c | 11 | ||||
| -rw-r--r-- | src/time/gmtime_r.c | 10 | ||||
| -rw-r--r-- | src/time/localtime.c | 12 | ||||
| -rw-r--r-- | src/time/localtime_r.c | 11 | ||||
| -rw-r--r-- | src/time/mktime.c | 24 | ||||
| -rw-r--r-- | src/time/nanosleep.c | 13 | ||||
| -rw-r--r-- | src/time/strftime.c | 172 | ||||
| -rw-r--r-- | src/time/strptime.c | 178 | ||||
| -rw-r--r-- | src/time/time.c | 12 | ||||
| -rw-r--r-- | src/time/times.c | 7 | ||||
| -rw-r--r-- | src/time/timezone.s | 27 | ||||
| -rw-r--r-- | src/time/tzset.c | 173 | ||||
| -rw-r--r-- | src/time/utime.c | 12 | 
25 files changed, 874 insertions, 0 deletions
| diff --git a/src/time/__asctime.c b/src/time/__asctime.c new file mode 100644 index 00000000..18535802 --- /dev/null +++ b/src/time/__asctime.c @@ -0,0 +1,27 @@ +#include <time.h> +#include <stdio.h> +#include <langinfo.h> + +const char *__langinfo(nl_item); + +char *__asctime(const struct tm *tm, char *buf) +{ +	/* FIXME: change __langinfo to __C_langinfo once we have locales */ +	if (snprintf(buf, 26, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n", +		__langinfo(ABDAY_1+tm->tm_wday), +		__langinfo(ABMON_1+tm->tm_mon), +		tm->tm_mday, tm->tm_hour, +		tm->tm_min, tm->tm_sec, +		1900 + tm->tm_year) >= 26) +	{ +		/* ISO C requires us to use the above format string, +		 * even if it will not fit in the buffer. Thus asctime_r +		 * is _supposed_ to crash if the fields in tm are too large. +		 * We follow this behavior and crash "gracefully" to warn +		 * application developers that they may not be so lucky +		 * on other implementations (e.g. stack smashing..). +		 */ +		*(int*)0 = 0; +	} +	return buf; +} diff --git a/src/time/__time.h b/src/time/__time.h new file mode 100644 index 00000000..967e5180 --- /dev/null +++ b/src/time/__time.h @@ -0,0 +1,9 @@ +time_t __tm_to_time(struct tm *); +struct tm *__time_to_tm(time_t, struct tm *); +void __tzset(void); +struct tm *__dst_adjust(struct tm *tm); + +extern long __timezone; +extern int __daylight; +extern int __dst_offset; +extern char *__tzname[2]; diff --git a/src/time/__time_to_tm.c b/src/time/__time_to_tm.c new file mode 100644 index 00000000..a1ebc452 --- /dev/null +++ b/src/time/__time_to_tm.c @@ -0,0 +1,81 @@ +#include <time.h> + +/* C defines the rounding for division in a nonsensical way */ +#define Q(a,b) ((a)>0 ? (a)/(b) : -(((b)-(a)-1)/(b))) + +#define DAYS_PER_400Y (365*400 + 97) +#define DAYS_PER_100Y (365*100 + 24) +#define DAYS_PER_4Y   (365*4   + 1) + +/* FIXME: use lldiv once it's fixed to compute quot,rem together */ +struct tm *__time_to_tm(time_t t, struct tm *tm) +{ +	/* months are march-based */ +	static const int days_thru_month[] = {31,61,92,122,153,184,214,245,275,306,337,366}; +	long long bigday; +	unsigned int day, year4, year100; +	int year, year400; +	int month; +	int leap; +	int hour, min, sec; +	int wday, mday, yday; + +	/* start from 2000-03-01 (multiple of 400 years) */ +	t += -946684800 - 86400*(31+29); + +	bigday = Q(t, 86400); +	sec = t-bigday*86400; + +	hour = sec/3600; +	sec -= hour*3600; +	min = sec/60; +	sec -= min*60; + +	/* 2000-03-01 was a wednesday */ +	wday = (3+bigday)%7; +	if (wday < 0) wday += 7; + +	t = -946684800LL - 86400*(31+29) + 9000000; +	 +	year400 = Q(bigday, DAYS_PER_400Y); +	day = bigday-year400*DAYS_PER_400Y; + +	year100 = day/DAYS_PER_100Y; +	if (year100 == 4) year100--; +	day -= year100*DAYS_PER_100Y; + +	year4 = day/DAYS_PER_4Y; +	if (year4 == 25) year4--; +	day -= year4*DAYS_PER_4Y; + +	year = day/365; +	if (year == 4) year--; +	day -= year*365; + +	leap = !year && (year4 || !year100); +	yday = day + 31+28 + leap; +	if (yday >= 365+leap) yday -= 365+leap; + +	year += 4*year4 + 100*year100 + 400*year400 + 2000-1900; + +	for (month=0; days_thru_month[month] <= day; month++); +	if (month) day -= days_thru_month[month-1]; +	month += 2; +	if (month >= 12) { +		month -= 12; +		year++; +	} + +	mday = day+1; + +	tm->tm_sec = sec; +	tm->tm_min = min; +	tm->tm_hour= hour; +	tm->tm_mday= mday; +	tm->tm_mon = month; +	tm->tm_year= year; +	tm->tm_wday= wday; +	tm->tm_yday= yday; + +	return tm; +} diff --git a/src/time/__tm_to_time.c b/src/time/__tm_to_time.c new file mode 100644 index 00000000..3fa15fad --- /dev/null +++ b/src/time/__tm_to_time.c @@ -0,0 +1,33 @@ +#include <time.h> + +/* C defines the rounding for division in a nonsensical way */ +#define Q(a,b) ((a)>0 ? (a)/(b) : -(((b)-(a)-1)/(b))) + +time_t __tm_to_time(struct tm *tm) +{ +	time_t year  = tm->tm_year + -100; +	int    month = tm->tm_mon; +	int    day   = tm->tm_mday; +	int z4, z100, z400; + +	/* normalize month */ +	if (month >= 12) { +		year += month/12; +		month %= 12; +	} else if (month < 0) { +		year += month/12; +		month %= 12; +		if (month) { +			month += 12; +			year--; +		} +	} +	z4 = Q(year - (month < 2), 4); +	z100 = Q(z4, 25); +	z400 = Q(z100, 4); +	day += year*365 + z4 - z100 + z400 + +		month[(int []){0,31,59,90,120,151,181,212,243,273,304,335}]; +	return (long long)day*86400 +		+ tm->tm_hour*3600 + tm->tm_min*60 + tm->tm_sec +		- -946684800; /* the dawn of time :) */ +} diff --git a/src/time/asctime.c b/src/time/asctime.c new file mode 100644 index 00000000..3102eb87 --- /dev/null +++ b/src/time/asctime.c @@ -0,0 +1,9 @@ +#include <time.h> + +char *__asctime(const struct tm *, char *); + +char *asctime(const struct tm *tm) +{ +	static char buf[26]; +	return __asctime(tm, buf); +} diff --git a/src/time/asctime_r.c b/src/time/asctime_r.c new file mode 100644 index 00000000..e51b8804 --- /dev/null +++ b/src/time/asctime_r.c @@ -0,0 +1,8 @@ +#include <time.h> + +char *__asctime(const struct tm *, char *); + +char *asctime_r(const struct tm *tm, char *buf) +{ +	return __asctime(tm, buf); +} diff --git a/src/time/clock.c b/src/time/clock.c new file mode 100644 index 00000000..2feddb36 --- /dev/null +++ b/src/time/clock.c @@ -0,0 +1,9 @@ +#include <time.h> +#include <sys/times.h> + +/* this function assumes 100 hz linux and corrects for it */ +clock_t clock() +{ +	struct tms tms; +	return (unsigned long)times(&tms)*10000; +} diff --git a/src/time/clock_gettime.c b/src/time/clock_gettime.c new file mode 100644 index 00000000..dab09d50 --- /dev/null +++ b/src/time/clock_gettime.c @@ -0,0 +1,7 @@ +#include <time.h> +#include "syscall.h" + +int clock_gettime(clockid_t clk, struct timespec *ts) +{ +	return syscall2(__NR_clock_gettime, clk, (long)ts); +} diff --git a/src/time/ctime.c b/src/time/ctime.c new file mode 100644 index 00000000..185ec554 --- /dev/null +++ b/src/time/ctime.c @@ -0,0 +1,6 @@ +#include <time.h> + +char *ctime(const time_t *t) +{ +	return asctime(localtime(t)); +} diff --git a/src/time/ctime_r.c b/src/time/ctime_r.c new file mode 100644 index 00000000..d2260a16 --- /dev/null +++ b/src/time/ctime_r.c @@ -0,0 +1,8 @@ +#include <time.h> + +char *ctime_r(const time_t *t, char *buf) +{ +	struct tm tm; +	localtime_r(t, &tm); +	return asctime_r(&tm, buf); +} diff --git a/src/time/difftime.c b/src/time/difftime.c new file mode 100644 index 00000000..80a18cc0 --- /dev/null +++ b/src/time/difftime.c @@ -0,0 +1,6 @@ +#include <time.h> + +double difftime(time_t t1, time_t t0) +{ +	return t1-t0; +} diff --git a/src/time/gettimeofday.c b/src/time/gettimeofday.c new file mode 100644 index 00000000..2b8a287d --- /dev/null +++ b/src/time/gettimeofday.c @@ -0,0 +1,9 @@ +#define SYSCALL_RETURN_ERRNO +#include <sys/time.h> +#include "syscall.h" + +int gettimeofday(struct timeval *tv, void *tz) +{ +	syscall2(__NR_gettimeofday, (long)tv, 0); +	return 0; +} diff --git a/src/time/gmtime.c b/src/time/gmtime.c new file mode 100644 index 00000000..d4d5d1f1 --- /dev/null +++ b/src/time/gmtime.c @@ -0,0 +1,11 @@ +#include <time.h> + +#include "__time.h" + +struct tm *gmtime(const time_t *t) +{ +	static struct tm tm; +	__time_to_tm(*t, &tm); +	tm.tm_isdst = 0; +	return &tm; +} diff --git a/src/time/gmtime_r.c b/src/time/gmtime_r.c new file mode 100644 index 00000000..5b565a65 --- /dev/null +++ b/src/time/gmtime_r.c @@ -0,0 +1,10 @@ +#include <time.h> + +#include "__time.h" + +struct tm *gmtime_r(const time_t *t, struct tm *result) +{ +	__time_to_tm(*t, result); +	result->tm_isdst = 0; +	return result; +} diff --git a/src/time/localtime.c b/src/time/localtime.c new file mode 100644 index 00000000..abd5e84d --- /dev/null +++ b/src/time/localtime.c @@ -0,0 +1,12 @@ +#include <time.h> + +#include "__time.h" + +struct tm *localtime(const time_t *t) +{ +	static struct tm tm; +	__tzset(); +	__time_to_tm(*t - __timezone, &tm); +	tm.tm_isdst = -1; +	return __dst_adjust(&tm); +} diff --git a/src/time/localtime_r.c b/src/time/localtime_r.c new file mode 100644 index 00000000..2bf10378 --- /dev/null +++ b/src/time/localtime_r.c @@ -0,0 +1,11 @@ +#include <time.h> + +#include "__time.h" + +struct tm *localtime_r(const time_t *t, struct tm *result) +{ +	__tzset(); +	__time_to_tm(*t - __timezone, result); +	result->tm_isdst = -1; +	return __dst_adjust(result); +} diff --git a/src/time/mktime.c b/src/time/mktime.c new file mode 100644 index 00000000..858cd50d --- /dev/null +++ b/src/time/mktime.c @@ -0,0 +1,24 @@ +#include <time.h> + +#include "__time.h" + +time_t mktime(struct tm *tm) +{ +	int isdst = tm->tm_isdst; +	time_t t, lt; + +	__tzset(); + +	tm->tm_sec += __timezone; +	if (isdst > 0) tm->tm_sec += __dst_offset; + +	t = __tm_to_time(tm); +	 +	lt = t - __timezone; +	if (isdst > 0) lt -= __dst_offset; +	__time_to_tm(lt, tm); + +	__dst_adjust(tm); +	 +	return t; +} diff --git a/src/time/nanosleep.c b/src/time/nanosleep.c new file mode 100644 index 00000000..5ac4c359 --- /dev/null +++ b/src/time/nanosleep.c @@ -0,0 +1,13 @@ +#include <unistd.h> +#include <time.h> +#include "syscall.h" +#include "libc.h" + +int nanosleep(const struct timespec *req, struct timespec *rem) +{ +	int ret; +	CANCELPT_BEGIN; +	ret = syscall2(__NR_nanosleep, (long)req, (long)rem); +	CANCELPT_END; +	return ret; +} diff --git a/src/time/strftime.c b/src/time/strftime.c new file mode 100644 index 00000000..f1b94631 --- /dev/null +++ b/src/time/strftime.c @@ -0,0 +1,172 @@ +#include <stdio.h> +#include <stdlib.h> +#include <langinfo.h> +#include <time.h> +#include "__time.h" + +// FIXME: integer overflows + +const char *__langinfo(nl_item); + +size_t strftime(char *s, size_t n, const char *f, const struct tm *tm) +{ +	nl_item item; +	int val; +	const char *fmt; +	size_t l; +	for (l=0; *f && l<n; f++) { +		if (*f == '%') { +do_fmt: +		switch (*++f) { +		case '%': +			goto literal; +		case 'E': +		case 'O': +			goto do_fmt; +		case 'a': +			item = ABDAY_1 + tm->tm_wday; +			goto nl_strcat; +		case 'A': +			item = DAY_1 + tm->tm_wday; +			goto nl_strcat; +		case 'h': +		case 'b': +			item = ABMON_1 + tm->tm_mon; +			goto nl_strcat; +		case 'B': +			item = MON_1 + tm->tm_mon; +			goto nl_strcat; +		case 'c': +			item = D_T_FMT; +			goto nl_strftime; +		case 'C': +			val = (1900+tm->tm_year) / 100; +			fmt = "%02d"; +			goto number; +		case 'd': +			val = tm->tm_mday; +			fmt = "%02d"; +			goto number; +		case 'D': +			fmt = "%m/%d/%y"; +			goto recu_strftime; +		case 'e': +			val = tm->tm_mday; +			fmt = "%2d"; +			goto number; +		case 'F': +			fmt = "%Y-%m-%d"; +			goto recu_strftime; +		case 'g': +			// FIXME +			val = 0; //week_based_year(tm)%100; +			fmt = "%02d"; +			goto number; +		case 'G': +			// FIXME +			val = 0; //week_based_year(tm); +			fmt = "%04d"; +			goto number; +		case 'H': +			val = tm->tm_hour; +			fmt = "%02d"; +			goto number; +		case 'I': +			val = tm->tm_hour; +			if (!val) val = 12; +			else if (val > 12) val -= 12; +			fmt = "%02d"; +			goto number; +		case 'j': +			val = tm->tm_yday+1; +			fmt = "%03d"; +			goto number; +		case 'm': +			val = tm->tm_mon+1; +			fmt = "%02d"; +			goto number; +		case 'M': +			val = tm->tm_min; +			fmt = "%02d"; +			goto number; +		case 'n': +			s[l++] = '\n'; +			continue; +		case 'p': +			item = tm->tm_hour >= 12 ? PM_STR : AM_STR; +			goto nl_strcat; +		case 'r': +			item = T_FMT_AMPM; +			goto nl_strftime; +		case 'R': +			fmt = "%H:%M"; +			goto recu_strftime; +		case 'S': +			val = tm->tm_sec; +			fmt = "%02d"; +			goto number; +		case 't': +			s[l++] = '\t'; +			continue; +		case 'T': +			fmt = "%H:%M:%S"; +			goto recu_strftime; +		case 'u': +			val = tm->tm_wday ? tm->tm_wday : 7; +			fmt = "%d"; +			goto number; +		case 'U': +		case 'V': +		case 'W': +			// FIXME: week number mess.. +			continue; +		case 'w': +			val = tm->tm_wday; +			fmt = "%d"; +			goto number; +		case 'x': +			item = D_FMT; +			goto nl_strftime; +		case 'X': +			item = T_FMT; +			goto nl_strftime; +		case 'y': +			val = tm->tm_year % 100; +			fmt = "%02d"; +			goto number; +		case 'Y': +			val = tm->tm_year + 1900; +			fmt = "%04d"; +			goto number; +		case 'z': +			if (tm->tm_isdst < 0) continue; +			val = -__timezone - (tm->tm_isdst ? __dst_offset : 0); +			l += snprintf(s+l, n-l, "%+.2d%.2d", val/3600, abs(val%3600)/60); +			continue; +		case 'Z': +			if (tm->tm_isdst < 0 || !__tzname[0] || !__tzname[0][0]) +				continue; +			l += snprintf(s+l, n-l, "%s", __tzname[!!tm->tm_isdst]); +			continue; +		default: +			return 0; +		} +		} +literal: +		s[l++] = *f; +		continue; +number: +		l += snprintf(s+l, n-l, fmt, val); +		continue; +nl_strcat: +		l += snprintf(s+l, n-l, "%s", __langinfo(item)); +		continue; +nl_strftime: +		fmt = __langinfo(item); +recu_strftime: +		l += strftime(s+l, n-l, fmt, tm); +	} +	if (l >= n) return 0; +	s[l] = 0; +	return l; +} diff --git a/src/time/strptime.c b/src/time/strptime.c new file mode 100644 index 00000000..db72e610 --- /dev/null +++ b/src/time/strptime.c @@ -0,0 +1,178 @@ +#include <stdio.h> +#include <stdlib.h> +#include <langinfo.h> +#include <time.h> + +const char *__langinfo(nl_item); + +char *strptime(const char *s, const char *f, struct tm *tm) +{ +	return NULL; +} + +#if 0 + +char *strptime(const char *s, const char *f, struct tm *tm) +{ +	nl_item item; +	int *dest; +	const char *fmt; +	for (; *f; f++) { +		if (isspace(*f)) goto whitespace; +		if (*f == '%') { +do_fmt: +		switch (*++f) { +		case '%': +			goto literal; +		case 'E': +		case 'O': +			goto do_fmt; +		case 'a': +			item = ABDAY_1 + tm->tm_wday; +			goto nl_strcat; +		case 'A': +			item = DAY_1 + tm->tm_wday; +			goto nl_strcat; +		case 'h': +		case 'b': +			item = ABMON_1 + tm->tm_mon; +			goto nl_strcat; +		case 'B': +			item = MON_1 + tm->tm_mon; +			goto nl_strcat; +		case 'c': +			item = D_T_FMT; +			goto nl_strftime; +		case 'C': +			val = (1900+tm->tm_year) / 100; +			fmt = "%02d"; +			goto number; +		case 'd': +			val = tm->tm_mday; +			fmt = "%02d"; +			goto number; +		case 'D': +			fmt = "%m/%d/%y"; +			goto recu_strftime; +		case 'e': +			val = tm->tm_mday; +			fmt = "%2d"; +			goto number; +		case 'F': +			fmt = "%Y-%m-%d"; +			goto recu_strftime; +		case 'g': +			// FIXME +			val = 0; //week_based_year(tm)%100; +			fmt = "%02d"; +			goto number; +		case 'G': +			// FIXME +			val = 0; //week_based_year(tm); +			fmt = "%04d"; +			goto number; +		case 'H': +			val = tm->tm_hour; +			fmt = "%02d"; +			goto number; +		case 'I': +			val = tm->tm_hour; +			if (!val) val = 12; +			else if (val > 12) val -= 12; +			fmt = "%02d"; +			goto number; +		case 'j': +			val = tm->tm_yday+1; +			fmt = "%03d"; +			goto number; +		case 'm': +			val = tm->tm_mon+1; +			fmt = "%02d"; +			goto number; +		case 'M': +			val = tm->tm_min; +			fmt = "%02d"; +			goto number; +		case 'n': +		case 't': +			goto whitespace; +		case 'p': +			item = tm->tm_hour >= 12 ? PM_STR : AM_STR; +			goto nl_strcat; +		case 'r': +			item = T_FMT_AMPM; +			goto nl_strftime; +		case 'R': +			fmt = "%H:%M"; +			goto recu_strftime; +		case 'S': +			val = tm->tm_sec; +			fmt = "%02d"; +			goto number; +		case 'T': +			fmt = "%H:%M:%S"; +			goto recu_strftime; +		case 'u': +			val = tm->tm_wday ? tm->tm_wday : 7; +			fmt = "%d"; +			goto number; +		case 'U': +		case 'V': +		case 'W': +			// FIXME: week number mess.. +			continue; +		case 'w': +			val = tm->tm_wday; +			fmt = "%d"; +			goto number; +		case 'x': +			item = D_FMT; +			goto nl_strftime; +		case 'X': +			item = T_FMT; +			goto nl_strftime; +		case 'y': +			val = tm->tm_year % 100; +			fmt = "%02d"; +			goto number; +		case 'Y': +			val = tm->tm_year + 1900; +			fmt = "%04d"; +			goto number; +		case 'z': +			if (tm->tm_isdst < 0) continue; +			val = timezone + (tm->tm_isdst) ? __dst_offset : 0; +			l += snprintf(s+l, n-l, "%+02d%02d", val/60, abs(val%60)); +			continue; +		case 'Z': +			if (tm->tm_isdst < 0 || !tzname[0] || !tzname[0][0]) +				continue; +			l += snprintf(s+l, n-l, "%s", tzname[!!tm->tm_isdst]); +			continue; +		} +		default: +			return NULL; +		} +literal: +		if (*s++ != *f) return NULL; +		continue; +whitespace: +		while(isspace(*s)) s++; +		continue; +number: +		l += snprintf(s+l, n-l, fmt, val); +		continue; +nl_strcat: +		l += snprintf(s+l, n-l, "%s", __langinfo(item)); +		continue; +nl_strftime: +		fmt = __langinfo(item); +recu_strftime: +		l += strftime(s+l, n-l, fmt, tm); +	} +	if (l >= n) return 0; +	s[l] = 0; +	return l; +} + +#endif diff --git a/src/time/time.c b/src/time/time.c new file mode 100644 index 00000000..3457dade --- /dev/null +++ b/src/time/time.c @@ -0,0 +1,12 @@ +#define SYSCALL_RETURN_ERRNO +#include <time.h> +#include <sys/time.h> +#include "syscall.h" + +time_t time(time_t *t) +{ +	struct timeval tv; +	syscall2(__NR_gettimeofday, (long)&tv, 0); +	if (t) *t = tv.tv_sec; +	return tv.tv_sec; +} diff --git a/src/time/times.c b/src/time/times.c new file mode 100644 index 00000000..e9b5a823 --- /dev/null +++ b/src/time/times.c @@ -0,0 +1,7 @@ +#include <sys/times.h> +#include "syscall.h" + +clock_t times(struct tms *tms) +{ +	return syscall1(__NR_times, (long)&tms); +} diff --git a/src/time/timezone.s b/src/time/timezone.s new file mode 100644 index 00000000..4e167b0b --- /dev/null +++ b/src/time/timezone.s @@ -0,0 +1,27 @@ +.data + +.global timezone +.global __timezone +.global daylight +.global __daylight +.global tzname +.global __tzname + +__timezone: +timezone: +	.long 0 +.size timezone,.-timezone +.size __timezone,.-__timezone + +__daylight: +daylight: +	.long 0 +.size daylight,.-daylight +.size __daylight,.-__daylight + +__tzname: +tzname: +	.long 0 +	.long 0 +.size tzname,.-tzname +.size __tzname,.-__tzname diff --git a/src/time/tzset.c b/src/time/tzset.c new file mode 100644 index 00000000..6d69957e --- /dev/null +++ b/src/time/tzset.c @@ -0,0 +1,173 @@ +#include <time.h> +#include <ctype.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include "libc.h" + +#include "__time.h" + +long  __timezone = 0; +int   __daylight = 0; +char *__tzname[2] = { 0, 0 }; +int   __dst_offset = 0; + +weak_alias(__timezone, timezone); +weak_alias(__daylight, daylight); +weak_alias(__tzname, tzname); +weak_alias(__dst_offset, dst_offset); + +static char std_name[TZNAME_MAX+1]; +static char dst_name[TZNAME_MAX+1]; + +/* all elements are zero-based */ +static struct rule { +	char month; +	char week; +	short day; +	int time; +} __dst_start, __dst_end; + +static void zname(char *d, char **s) +{ +	int i; +	for (i=0; i<TZNAME_MAX && isalpha(d[i]=**s); i++, (*s)++); +	d[i] = 0; +} + +static int hhmmss(char **s) +{ +	int ofs = strtol(*s, s, 10)*3600; +	if (ofs >= 0) { +		if (**s == ':') ofs += strtol(*s+1, s, 10)*60; +		if (**s == ':') ofs += strtol(*s+1, s, 10); +	} else { +		if (**s == ':') ofs -= strtol(*s+1, s, 10)*60; +		if (**s == ':') ofs -= strtol(*s+1, s, 10); +	} +	return ofs; +} + +static int dstrule(struct rule *rule, char **s) +{ +	if (**s != ',') return -1; +	switch (*++*s) { +	case 'J': +		rule->month = 'J'; +		rule->day = strtol(*s+1, s, 10)-1; +		break; +	case 'M': +		rule->month = strtol(*s+1, s, 10)-1; +		if (**s != '.' || rule->month < 0 || rule->month > 11) +			return -1; +		rule->week = strtol(*s+1, s, 10)-1; +		if (**s != '.' || rule->week < 0 || rule->week > 4) +			return -1; +		rule->day = strtol(*s+1, s, 10); +		if (rule->day < 0 || rule->day > 6) +			return -1; +		break; +	default: +		rule->month = 'L'; +		rule->day = strtol(*s+1, s, 10); +		break; +	} +	if (**s == '/') { +		(*s)++; +		rule->time = hhmmss(s); +	} else rule->time = 7200; +	return 0; +} + +void tzset(void) +{ +	char *z, *a; +	 +	strcpy(std_name, "GMT"); +	strcpy(dst_name, "GMT"); +	__tzname[0] = std_name; +	__tzname[1] = dst_name; +	__timezone = 0; +	__daylight = 0; +	 +	if (!(z = getenv("TZ")) || !isalpha(*z)) return; + +	zname(std_name, &z); +	__timezone = hhmmss(&z); + +	zname(dst_name, &z); +	if (dst_name[0]) __daylight=1; +	a = z; +	__dst_offset = hhmmss(&z) - __timezone; +	if (z==a) __dst_offset = -3600; + +	if (dstrule(&__dst_start, &z) || dstrule(&__dst_end, &z)) +		__daylight = 0; +} + +void __tzset(void) +{ +	static int lock, init; +	if (init) return; +	LOCK(&lock); +	if (!init) tzset(); +	init=1; +	UNLOCK(&lock); +} + +static int is_leap(int year) +{ +	year -= 100; +	return !(year&3) && ((year%100) || !(year%400)); +} + +static int cutoff_yday(struct tm *tm, struct rule *rule) +{ +	static const char days_in_month[] = {31,28,31,30,31,30,31,31,30,31,30,31}; +	static const int first_day[] = {0,31,59,90,120,151,181,212,243,273,304,335}; +	int yday, mday, leap; +	 +	switch (rule->month) { +	case 'J': +		return rule->day + (tm->tm_mon > 1 && is_leap(tm->tm_year)); +	case 'L': +		return rule->day; +	default: +		yday = first_day[rule->month]; +		leap = is_leap(tm->tm_year); +		if (rule->month > 1 && leap) yday++; +		mday = (rule->day - (yday + tm->tm_wday - tm->tm_yday) + 1400)%7 + 7*rule->week; +		if (mday >= days_in_month[rule->month] + (leap && rule->month == 1)) +			mday -= 7; +		return mday + yday; +	} +} + +struct tm *__dst_adjust(struct tm *tm) +{ +	time_t t; +	int start, end, secs; +	int after_start, before_end; + +	if (tm->tm_isdst >= 0) return tm; +	if (!__daylight) { +		tm->tm_isdst = 0; +		return tm; +	} +	 +	secs = tm->tm_hour*3600 + tm->tm_min*60 + tm->tm_sec; +	start = cutoff_yday(tm, &__dst_start); +	end = cutoff_yday(tm, &__dst_end); + +	after_start = (tm->tm_yday > start || (tm->tm_yday == start && secs >= __dst_start.time)); +	before_end = (tm->tm_yday < end || (tm->tm_yday == end && secs < __dst_end.time)); + +	if ((after_start && before_end) || ((end < start) && (after_start || before_end))) { +		tm->tm_sec -= __dst_offset; +		tm->tm_isdst = 1; +		t = __tm_to_time(tm); +		return __time_to_tm(t, tm); +	} else tm->tm_isdst = 0; + +	return tm; +} diff --git a/src/time/utime.c b/src/time/utime.c new file mode 100644 index 00000000..56e9e13a --- /dev/null +++ b/src/time/utime.c @@ -0,0 +1,12 @@ +#include <utime.h> +#include "syscall.h" + +int utime(const char *path, const struct utimbuf *times) +{ +	long ktimes[2]; +	if (times) { +		ktimes[0] = times->actime; +		ktimes[1] = times->modtime; +	} +	return syscall2(__NR_utime, (long)path, times ? (long)ktimes : 0); +} | 
